mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-04 15:25:06 -05:00
Compare commits
152 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
009f1a5ae8 | ||
|
|
4f1418abf9 | ||
|
|
79b348f075 | ||
|
|
9d88c028e2 | ||
|
|
51172b3510 | ||
|
|
892636036a | ||
|
|
4cf6b29397 | ||
|
|
571359b366 | ||
|
|
0f009e7718 | ||
|
|
24effd7340 | ||
|
|
5289fc5f80 | ||
|
|
ca49304bd6 | ||
|
|
b7fbac617d | ||
|
|
839e9aa4af | ||
|
|
c5ac15ad33 | ||
|
|
598cd10c34 | ||
|
|
1885729024 | ||
|
|
2127f63961 | ||
|
|
97a8b1e43b | ||
|
|
aeee1feda6 | ||
|
|
18d9243eb9 | ||
|
|
1aa4827b3b | ||
|
|
ed1077a788 | ||
|
|
356c475a6a | ||
|
|
9ac582fa35 | ||
|
|
8c75f44603 | ||
|
|
0a63ad95ce | ||
|
|
d274fe44da | ||
|
|
6d1cb58d8f | ||
|
|
784122d44f | ||
|
|
32fb8d41ca | ||
|
|
4993c35e11 | ||
|
|
6a5665ca58 | ||
|
|
e5cf006378 | ||
|
|
0e51552d2d | ||
|
|
cc007ad93b | ||
|
|
3096926547 | ||
|
|
d48f012809 | ||
|
|
def137bc80 | ||
|
|
3e0272e55f | ||
|
|
be503bbcf6 | ||
|
|
72bf3d26eb | ||
|
|
cc20ead3dc | ||
|
|
fd8fbcd090 | ||
|
|
77bd0f83fe | ||
|
|
32a82a38fd | ||
|
|
66e097e3e6 | ||
|
|
51d77d6cfc | ||
|
|
2bb0769516 | ||
|
|
58da0c0ad2 | ||
|
|
c10b66b579 | ||
|
|
55a90c3735 | ||
|
|
962afb9e7d | ||
|
|
7abd982f87 | ||
|
|
c099aac79c | ||
|
|
828e6ce30f | ||
|
|
dc08cbfe59 | ||
|
|
3bdcce6903 | ||
|
|
d93aa10bac | ||
|
|
de4ecc72d1 | ||
|
|
db54bfc0c1 | ||
|
|
72ee80debe | ||
|
|
a3436c26f0 | ||
|
|
b0f5024d56 | ||
|
|
eae4b2abe5 | ||
|
|
ff03b813b0 | ||
|
|
4e747da4b4 | ||
|
|
99e3c67a81 | ||
|
|
c4a2550518 | ||
|
|
4ef944b734 | ||
|
|
0f04baeb97 | ||
|
|
bf7f63eaed | ||
|
|
59cf4e0b96 | ||
|
|
3fc72c0cfa | ||
|
|
ad69f4f32b | ||
|
|
81c2b2e886 | ||
|
|
c9f03fb222 | ||
|
|
b0fe443632 | ||
|
|
8882fb21e0 | ||
|
|
7d551d34a0 | ||
|
|
feef0dd983 | ||
|
|
d29f7b7c70 | ||
|
|
e3cd248f0d | ||
|
|
27e20a568b | ||
|
|
80316de3b8 | ||
|
|
f9e2a5852d | ||
|
|
500c9cbf3b | ||
|
|
46714fec2d | ||
|
|
e1d9a57bd0 | ||
|
|
1b82604f61 | ||
|
|
d69ac07183 | ||
|
|
519796de37 | ||
|
|
ea4811b3b3 | ||
|
|
951f14ae06 | ||
|
|
428f9e4228 | ||
|
|
ea425bf01e | ||
|
|
8567a0e466 | ||
|
|
f6bf12bdcd | ||
|
|
e8968ea429 | ||
|
|
cf10ce1b68 | ||
|
|
15dc83420d | ||
|
|
37dbc211cd | ||
|
|
ed78cda6ad | ||
|
|
faff931a76 | ||
|
|
1e68671690 | ||
|
|
8eb167fd21 | ||
|
|
bc46174e98 | ||
|
|
b86c89460a | ||
|
|
03541f3626 | ||
|
|
39a462496a | ||
|
|
7ba8994838 | ||
|
|
8da025da99 | ||
|
|
5dc7242703 | ||
|
|
11bffa0d55 | ||
|
|
5f6f265f80 | ||
|
|
bf92314dc4 | ||
|
|
a3fda9f992 | ||
|
|
cd34b377aa | ||
|
|
145423068b | ||
|
|
fb4c3f31c0 | ||
|
|
60049f1551 | ||
|
|
e555548dda | ||
|
|
eedf61b3a2 | ||
|
|
ab54f76a38 | ||
|
|
f8df4789b1 | ||
|
|
6366ebc17e | ||
|
|
3a2d33d5a3 | ||
|
|
1afd5b23d7 | ||
|
|
17fb9e3709 | ||
|
|
7a7295992f | ||
|
|
526974366f | ||
|
|
51fe589aeb | ||
|
|
28cf4acf13 | ||
|
|
ee2220f2e7 | ||
|
|
a6ec6ec3ac | ||
|
|
4f5343f086 | ||
|
|
79c7384e5e | ||
|
|
75beeaf2b0 | ||
|
|
f4ed2abdca | ||
|
|
11a5c7337a | ||
|
|
972c476c5a | ||
|
|
a8c8f2f309 | ||
|
|
a0d2513be6 | ||
|
|
43dc0b3295 | ||
|
|
195ff5c51b | ||
|
|
e49aececce | ||
|
|
814b07c3a2 | ||
|
|
3470ab66f0 | ||
|
|
6901df5c18 | ||
|
|
bddb3b3228 | ||
|
|
dfe877144a | ||
|
|
59a9b7a9f6 |
@@ -134,4 +134,6 @@ Makefile : Makefile.in configure
|
||||
.deps/%.d: %.c | .deps
|
||||
@$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@
|
||||
|
||||
ifndef NODEPS
|
||||
-include $(ALL_OBJS:%.o=.deps/%.d)
|
||||
endif
|
||||
|
||||
26
NEWS
26
NEWS
@@ -5,20 +5,33 @@ Enhancements
|
||||
------------
|
||||
* Add support for Network Time Security (NTS) authentication
|
||||
* Add support for AES-CMAC keys (AES128, AES256) with Nettle
|
||||
* Add support for maxsamples of 1 for faster update with -q/-Q option
|
||||
* Add authselectmode directive to control selection of unauthenticated sources
|
||||
* Add binddevice, bindacqdevice, bindcmddevice directives
|
||||
* Add confdir directive to better support fragmented configuration
|
||||
* Add sourcedir directive and "reload sources" command to support
|
||||
dynamic NTP sources specified in files
|
||||
* Add dscp directive to set Differentiated Services Code Point (DSCP)
|
||||
* Add -L option to limit log messages by severity
|
||||
* Add -p option to print whole configuration with included files
|
||||
* Allow maxsamples to be set to 1 for faster update with -q/-Q option
|
||||
* Avoid replacing NTP sources with sources that have unreachable address
|
||||
* Improve pools to repeat name resolution to get "maxsources" sources
|
||||
* Improve source selection with trusted sources
|
||||
* Improve NTP loop test to prevent synchronisation to itself
|
||||
* Repeat iburst when NTP source is switched from offline state to online
|
||||
* Update clock synchronisation status and leap status more frequently
|
||||
* Update seccomp filter
|
||||
* Add "add pool" command
|
||||
* Add "reset sources" command to drop all measurements
|
||||
* Add authdata command to print details about NTP authentication
|
||||
* Add selectdata command to print details about source selection
|
||||
* Add -N option and sourcename command to print original names of sources
|
||||
* Add -a option to sources/sourcestats command to print unresolved sources
|
||||
* Add reset command to drop all measurements
|
||||
* Add -a option to some commands to print also unresolved sources
|
||||
* Add -k, -p, -r options to clients command to select, limit, reset data
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Don't set interface for NTP responses to allow asymmetric routing
|
||||
* Handle RTCs that don't support interrupts
|
||||
* Respond to command requests with correct address on multihomed hosts
|
||||
|
||||
@@ -26,6 +39,13 @@ Removed features
|
||||
----------------
|
||||
* Drop support for RIPEMD keys (RMD128, RMD160, RMD256, RMD320)
|
||||
|
||||
New in version 3.5.1
|
||||
====================
|
||||
|
||||
Security fixes
|
||||
--------------
|
||||
* Create new file when writing pidfile (CVE-2020-14367)
|
||||
|
||||
New in version 3.5
|
||||
==================
|
||||
|
||||
|
||||
40
README
40
README
@@ -29,9 +29,7 @@ What will chrony run on?
|
||||
|
||||
The software is known to work on Linux, FreeBSD, NetBSD, macOS and
|
||||
Solaris. Closely related systems may work too. Any other system will
|
||||
likely require a porting exercise. You would need to start from one
|
||||
of the existing system-specific drivers and look into the quirks of
|
||||
certain system calls and the kernel on your target system.
|
||||
likely require a porting exercise.
|
||||
|
||||
How do I set it up?
|
||||
===================
|
||||
@@ -55,24 +53,20 @@ Where are new versions announced?
|
||||
=================================
|
||||
|
||||
There is a low volume mailing list where new versions and other
|
||||
important news relating to chrony is announced. You can join this list
|
||||
important news relating to chrony are announced. You can join this list
|
||||
by sending mail with the subject "subscribe" to
|
||||
|
||||
chrony-announce-request@chrony.tuxfamily.org
|
||||
|
||||
These messages will be copied to chrony-users (see below).
|
||||
|
||||
How can I get support for chrony?
|
||||
and where can I discuss new features, possible bugs etc?
|
||||
========================================================
|
||||
=================================
|
||||
|
||||
There are 3 mailing lists relating to chrony. chrony-announce was
|
||||
mentioned above. chrony-users is a users' discussion list, e.g. for
|
||||
general questions and answers about using chrony. chrony-dev is a more
|
||||
technical list, e.g. for discussing how new features should be
|
||||
implemented, exchange of information between developers etc. To
|
||||
subscribe to either of these lists, send a message with the subject
|
||||
"subscribe" to
|
||||
There are two other mailing lists relating to chrony. chrony-users is a
|
||||
discussion list for users, e.g. for questions about chrony configuration
|
||||
and bug reports. chrony-dev is a more technical list for developers,
|
||||
e.g. for submitting patches and discussing how new features should be
|
||||
implemented. To subscribe to either of these lists, send a message with
|
||||
the subject "subscribe" to
|
||||
|
||||
chrony-users-request@chrony.tuxfamily.org
|
||||
or
|
||||
@@ -80,12 +74,6 @@ chrony-dev-request@chrony.tuxfamily.org
|
||||
|
||||
as applicable.
|
||||
|
||||
When you are reporting a bug, please send us all the information you can.
|
||||
Unfortunately, chrony has proven to be one of those programs where it is very
|
||||
difficult to reproduce bugs in a different environment. So we may have to
|
||||
interact with you quite a lot to obtain enough extra logging and tracing to
|
||||
pin-point the problem in some cases. Please be patient and plan for this!
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
@@ -100,12 +88,13 @@ Miroslav Lichvar <mlichvar@redhat.com>
|
||||
Acknowledgements
|
||||
================
|
||||
|
||||
In writing the chronyd program, extensive use has been made of RFC 1305
|
||||
and RFC 5905, written by David Mills. The source code of the NTP reference
|
||||
implementation has been used to check the details of the protocol.
|
||||
In writing the chronyd program, extensive use has been made of the NTPv3 (RFC
|
||||
1305) and NTPv4 (RFC 5905) specification. The source code of the xntpd/ntpd
|
||||
implementation written by Dennis Fergusson, Lars Mathiesen, David Mills, and
|
||||
others, has been used to check the details of the protocol.
|
||||
|
||||
The following people have provided patches and other major contributions
|
||||
to the program :
|
||||
to chrony:
|
||||
|
||||
Lonnie Abelbeck <lonnie@abelbeck.com>
|
||||
Benny Lyne Amorsen <benny@amorsen.dk>
|
||||
@@ -121,6 +110,7 @@ Bryan Christianson <bryan@whatroute.net>
|
||||
Juliusz Chroboczek <jch@pps.jussieu.fr>
|
||||
Christian Ehrhardt <christian.ehrhardt@canonical.com>
|
||||
Paul Elliott <pelliott@io.com>
|
||||
Robert Fairley <rfairley@redhat.com>
|
||||
Stefan R. Filipek <srfilipek@gmail.com>
|
||||
Mike Fleetwood <mike@rockover.demon.co.uk>
|
||||
Alexander Gretencord <arutha@gmx.de>
|
||||
|
||||
94
candm.h
94
candm.h
@@ -103,8 +103,12 @@
|
||||
#define REQ_ONOFFLINE 63
|
||||
#define REQ_ADD_SOURCE 64
|
||||
#define REQ_NTP_SOURCE_NAME 65
|
||||
#define REQ_RESET 66
|
||||
#define N_REQUEST_TYPES 67
|
||||
#define REQ_RESET_SOURCES 66
|
||||
#define REQ_AUTH_DATA 67
|
||||
#define REQ_CLIENT_ACCESSES_BY_INDEX3 68
|
||||
#define REQ_SELECT_DATA 69
|
||||
#define REQ_RELOAD_SOURCES 70
|
||||
#define N_REQUEST_TYPES 71
|
||||
|
||||
/* Structure used to exchange timespecs independent of time_t size */
|
||||
typedef struct {
|
||||
@@ -267,7 +271,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
int8_t name[256];
|
||||
uint8_t name[256];
|
||||
uint32_t port;
|
||||
int32_t minpoll;
|
||||
int32_t maxpoll;
|
||||
@@ -320,6 +324,8 @@ typedef struct {
|
||||
typedef struct {
|
||||
uint32_t first_index;
|
||||
uint32_t n_clients;
|
||||
uint32_t min_hits;
|
||||
uint32_t reset;
|
||||
int32_t EOR;
|
||||
} REQ_ClientAccessesByIndex;
|
||||
|
||||
@@ -351,6 +357,16 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_NTPSourceName;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
int32_t EOR;
|
||||
} REQ_AuthData;
|
||||
|
||||
typedef struct {
|
||||
uint32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_SelectData;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define PKT_TYPE_CMD_REQUEST 1
|
||||
@@ -389,7 +405,8 @@ typedef struct {
|
||||
Version 6 (no authentication) : changed format of client accesses by index
|
||||
(using new request/reply types) and manual timestamp, added new fields and
|
||||
flags to NTP source request and report, made length of manual list constant,
|
||||
added new commands: ntpdata, refresh, serverstats, shutdown
|
||||
added new commands: authdata, ntpdata, onoffline, refresh, reset,
|
||||
selectdata, serverstats, shutdown, sourcename
|
||||
*/
|
||||
|
||||
#define PROTO_VERSION_NUMBER 6
|
||||
@@ -403,8 +420,8 @@ typedef struct {
|
||||
#define PROTO_VERSION_PADDING 6
|
||||
|
||||
/* The maximum length of padding in request packet, currently
|
||||
defined by MANUAL_LIST */
|
||||
#define MAX_PADDING_LENGTH 396
|
||||
defined by CLIENT_ACCESSES_BY_INDEX3 */
|
||||
#define MAX_PADDING_LENGTH 484
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -453,7 +470,9 @@ typedef struct {
|
||||
REQ_ReselectDistance reselect_distance;
|
||||
REQ_SmoothTime smoothtime;
|
||||
REQ_NTPData ntp_data;
|
||||
REQ_NTPData ntp_source_name;
|
||||
REQ_NTPSourceName ntp_source_name;
|
||||
REQ_AuthData auth_data;
|
||||
REQ_SelectData select_data;
|
||||
} data; /* Command specific parameters */
|
||||
|
||||
/* Padding used to prevent traffic amplification. It only defines the
|
||||
@@ -491,7 +510,11 @@ typedef struct {
|
||||
#define RPY_MANUAL_TIMESTAMP2 17
|
||||
#define RPY_MANUAL_LIST2 18
|
||||
#define RPY_NTP_SOURCE_NAME 19
|
||||
#define N_REPLY_TYPES 20
|
||||
#define RPY_AUTH_DATA 20
|
||||
#define RPY_CLIENT_ACCESSES_BY_INDEX3 21
|
||||
#define RPY_SERVER_STATS2 22
|
||||
#define RPY_SELECT_DATA 23
|
||||
#define N_REPLY_TYPES 24
|
||||
|
||||
/* Status codes */
|
||||
#define STT_SUCCESS 0
|
||||
@@ -537,11 +560,6 @@ typedef struct {
|
||||
#define RPY_SD_ST_CANDIDATE 4
|
||||
#define RPY_SD_ST_OUTLIER 5
|
||||
|
||||
#define RPY_SD_FLAG_NOSELECT 0x1
|
||||
#define RPY_SD_FLAG_PREFER 0x2
|
||||
#define RPY_SD_FLAG_TRUST 0x4
|
||||
#define RPY_SD_FLAG_REQUIRE 0x8
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
int16_t poll;
|
||||
@@ -609,14 +627,17 @@ typedef struct {
|
||||
typedef struct {
|
||||
IPAddr ip;
|
||||
uint32_t ntp_hits;
|
||||
uint32_t nke_hits;
|
||||
uint32_t cmd_hits;
|
||||
uint32_t ntp_drops;
|
||||
uint32_t nke_drops;
|
||||
uint32_t cmd_drops;
|
||||
int8_t ntp_interval;
|
||||
int8_t nke_interval;
|
||||
int8_t cmd_interval;
|
||||
int8_t ntp_timeout_interval;
|
||||
int8_t pad;
|
||||
uint32_t last_ntp_hit_ago;
|
||||
uint32_t last_nke_hit_ago;
|
||||
uint32_t last_cmd_hit_ago;
|
||||
} RPY_ClientAccesses_Client;
|
||||
|
||||
@@ -630,10 +651,13 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
uint32_t ntp_hits;
|
||||
uint32_t nke_hits;
|
||||
uint32_t cmd_hits;
|
||||
uint32_t ntp_drops;
|
||||
uint32_t nke_drops;
|
||||
uint32_t cmd_drops;
|
||||
uint32_t log_drops;
|
||||
uint32_t ntp_auth_hits;
|
||||
int32_t EOR;
|
||||
} RPY_ServerStats;
|
||||
|
||||
@@ -708,10 +732,48 @@ typedef struct {
|
||||
} RPY_NTPData;
|
||||
|
||||
typedef struct {
|
||||
int8_t name[256];
|
||||
uint8_t name[256];
|
||||
int32_t EOR;
|
||||
} RPY_NTPSourceName;
|
||||
|
||||
#define RPY_AD_MD_NONE 0
|
||||
#define RPY_AD_MD_SYMMETRIC 1
|
||||
#define RPY_AD_MD_NTS 2
|
||||
|
||||
typedef struct {
|
||||
uint16_t mode;
|
||||
uint16_t key_type;
|
||||
uint32_t key_id;
|
||||
uint16_t key_length;
|
||||
uint16_t ke_attempts;
|
||||
uint32_t last_ke_ago;
|
||||
uint16_t cookies;
|
||||
uint16_t cookie_length;
|
||||
uint16_t nak;
|
||||
uint16_t pad;
|
||||
int32_t EOR;
|
||||
} RPY_AuthData;
|
||||
|
||||
#define RPY_SD_OPTION_NOSELECT 0x1
|
||||
#define RPY_SD_OPTION_PREFER 0x2
|
||||
#define RPY_SD_OPTION_TRUST 0x4
|
||||
#define RPY_SD_OPTION_REQUIRE 0x8
|
||||
|
||||
typedef struct {
|
||||
uint32_t ref_id;
|
||||
IPAddr ip_addr;
|
||||
uint8_t state_char;
|
||||
uint8_t authentication;
|
||||
uint8_t pad[2];
|
||||
uint16_t conf_options;
|
||||
uint16_t eff_options;
|
||||
uint32_t last_sample_ago;
|
||||
Float score;
|
||||
Float lo_limit;
|
||||
Float hi_limit;
|
||||
int32_t EOR;
|
||||
} RPY_SelectData;
|
||||
|
||||
typedef struct {
|
||||
uint8_t version;
|
||||
uint8_t pkt_type;
|
||||
@@ -742,6 +804,8 @@ typedef struct {
|
||||
RPY_Smoothing smoothing;
|
||||
RPY_NTPData ntp_data;
|
||||
RPY_NTPSourceName ntp_source_name;
|
||||
RPY_AuthData auth_data;
|
||||
RPY_SelectData select_data;
|
||||
} data; /* Reply specific parameters */
|
||||
|
||||
} CMD_Reply;
|
||||
|
||||
365
client.c
365
client.c
@@ -222,7 +222,7 @@ open_socket(struct Address *addr)
|
||||
|
||||
switch (addr->type) {
|
||||
case SCK_ADDR_IP:
|
||||
sock_fd = SCK_OpenUdpSocket(&addr->addr.ip, NULL, 0);
|
||||
sock_fd = SCK_OpenUdpSocket(&addr->addr.ip, NULL, NULL, 0);
|
||||
break;
|
||||
case SCK_ADDR_UNIX:
|
||||
/* Construct path of our socket. Use the same directory as the server
|
||||
@@ -960,39 +960,12 @@ process_cmd_cmddenyall(CMD_Request *msg, char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
accheck_getaddr(char *line, IPAddr *addr)
|
||||
{
|
||||
unsigned long a, b, c, d;
|
||||
IPAddr ip;
|
||||
char *p;
|
||||
p = line;
|
||||
if (!*p) {
|
||||
return 0;
|
||||
} else {
|
||||
if (sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d) == 4) {
|
||||
addr->family = IPADDR_INET4;
|
||||
addr->addr.in4 = (a<<24) | (b<<16) | (c<<8) | d;
|
||||
return 1;
|
||||
} else {
|
||||
if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
|
||||
return 0;
|
||||
} else {
|
||||
*addr = ip;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_accheck(CMD_Request *msg, char *line)
|
||||
{
|
||||
IPAddr ip;
|
||||
msg->command = htons(REQ_ACCHECK);
|
||||
if (accheck_getaddr(line, &ip)) {
|
||||
if (DNS_Name2IPAddress(line, &ip, 1) == DNS_Success) {
|
||||
UTI_IPHostToNetwork(&ip, &msg->data.ac_check.ip);
|
||||
return 1;
|
||||
} else {
|
||||
@@ -1008,7 +981,7 @@ process_cmd_cmdaccheck(CMD_Request *msg, char *line)
|
||||
{
|
||||
IPAddr ip;
|
||||
msg->command = htons(REQ_CMDACCHECK);
|
||||
if (accheck_getaddr(line, &ip)) {
|
||||
if (DNS_Name2IPAddress(line, &ip, 1) == DNS_Success) {
|
||||
UTI_IPHostToNetwork(&ip, &msg->data.ac_check.ip);
|
||||
return 1;
|
||||
} else {
|
||||
@@ -1084,11 +1057,11 @@ process_cmd_add_source(CMD_Request *msg, char *line)
|
||||
word = line;
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
if (!strcmp(word, "server")) {
|
||||
if (!strcasecmp(word, "server")) {
|
||||
type = REQ_ADDSRC_SERVER;
|
||||
} else if (!strcmp(word, "peer")) {
|
||||
} else if (!strcasecmp(word, "peer")) {
|
||||
type = REQ_ADDSRC_PEER;
|
||||
} else if (!strcmp(word, "pool")) {
|
||||
} else if (!strcasecmp(word, "pool")) {
|
||||
type = REQ_ADDSRC_POOL;
|
||||
} else {
|
||||
LOG(LOGS_ERR, "Invalid syntax for add command");
|
||||
@@ -1120,7 +1093,7 @@ process_cmd_add_source(CMD_Request *msg, char *line)
|
||||
assert(0);
|
||||
strncpy((char *)msg->data.ntp_source.name, data.name,
|
||||
sizeof (msg->data.ntp_source.name));
|
||||
msg->data.ntp_source.port = htonl((unsigned long) data.port);
|
||||
msg->data.ntp_source.port = htonl(data.port);
|
||||
msg->data.ntp_source.minpoll = htonl(data.params.minpoll);
|
||||
msg->data.ntp_source.maxpoll = htonl(data.params.maxpoll);
|
||||
msg->data.ntp_source.presend_minpoll = htonl(data.params.presend_minpoll);
|
||||
@@ -1209,29 +1182,32 @@ give_help(void)
|
||||
"Time sources:\0\0"
|
||||
"sources [-a] [-v]\0Display information about current sources\0"
|
||||
"sourcestats [-a] [-v]\0Display statistics about collected measurements\0"
|
||||
"selectdata [-a] [-v]\0Display information about source selection\0"
|
||||
"reselect\0Force reselecting synchronisation source\0"
|
||||
"reselectdist <dist>\0Modify reselection distance\0"
|
||||
"\0\0"
|
||||
"NTP sources:\0\0"
|
||||
"activity\0Check how many NTP sources are online/offline\0"
|
||||
"authdata [-a] [-v]\0Display information about authentication\0"
|
||||
"ntpdata [<address>]\0Display information about last valid measurement\0"
|
||||
"add server <name> [options]\0Add new NTP server\0"
|
||||
"add pool <name> [options]\0Add new pool of NTP servers\0"
|
||||
"add peer <name> [options]\0Add new NTP peer\0"
|
||||
"delete <address>\0Remove server or peer\0"
|
||||
"burst <n-good>/<n-max> [<mask>/<address>]\0Start rapid set of measurements\0"
|
||||
"burst <n-good>/<n-max> [[<mask>/]<address>]\0Start rapid set of measurements\0"
|
||||
"maxdelay <address> <delay>\0Modify maximum valid sample delay\0"
|
||||
"maxdelayratio <address> <ratio>\0Modify maximum valid delay/minimum ratio\0"
|
||||
"maxdelaydevratio <address> <ratio>\0Modify maximum valid delay/deviation ratio\0"
|
||||
"minpoll <address> <poll>\0Modify minimum polling interval\0"
|
||||
"maxpoll <address> <poll>\0Modify maximum polling interval\0"
|
||||
"minstratum <address> <stratum>\0Modify minimum stratum\0"
|
||||
"offline [<mask>/<address>]\0Set sources in subnet to offline status\0"
|
||||
"online [<mask>/<address>]\0Set sources in subnet to online status\0"
|
||||
"offline [[<mask>/]<address>]\0Set sources in subnet to offline status\0"
|
||||
"online [[<mask>/]<address>]\0Set sources in subnet to online status\0"
|
||||
"onoffline\0Set all sources to online or offline status\0"
|
||||
"\0according to network configuration\0"
|
||||
"polltarget <address> <target>\0Modify poll target\0"
|
||||
"refresh\0Refresh IP addresses\0"
|
||||
"reload sources\0Re-read *.sources files\0"
|
||||
"sourcename <address>\0Display original name\0"
|
||||
"\0\0"
|
||||
"Manual time input:\0\0"
|
||||
@@ -1242,7 +1218,7 @@ give_help(void)
|
||||
"\0(e.g. Sep 25, 2015 16:30:05 or 16:30:05)\0"
|
||||
"\0\0NTP access:\0\0"
|
||||
"accheck <address>\0Check whether address is allowed\0"
|
||||
"clients\0Report on clients that have accessed the server\0"
|
||||
"clients [-p <packets>] [-k] [-r]\0Report on clients that accessed the server\0"
|
||||
"serverstats\0Display statistics of the server\0"
|
||||
"allow [<subnet>]\0Allow access to subnet as a default\0"
|
||||
"allow all [<subnet>]\0Allow access to subnet and all children\0"
|
||||
@@ -1269,7 +1245,7 @@ give_help(void)
|
||||
"cyclelogs\0Close and re-open log files\0"
|
||||
"dump\0Dump measurements and NTS keys/cookies\0"
|
||||
"rekey\0Re-read keys\0"
|
||||
"reset\0Drop all measurements\0"
|
||||
"reset sources\0Drop all measurements\0"
|
||||
"shutdown\0Stop daemon\0"
|
||||
"\0\0"
|
||||
"Client commands:\0\0"
|
||||
@@ -1299,8 +1275,12 @@ enum {
|
||||
TAB_COMPLETE_BASE_CMDS,
|
||||
TAB_COMPLETE_ADD_OPTS,
|
||||
TAB_COMPLETE_MANUAL_OPTS,
|
||||
TAB_COMPLETE_RELOAD_OPTS,
|
||||
TAB_COMPLETE_RESET_OPTS,
|
||||
TAB_COMPLETE_SOURCES_OPTS,
|
||||
TAB_COMPLETE_SOURCESTATS_OPTS,
|
||||
TAB_COMPLETE_AUTHDATA_OPTS,
|
||||
TAB_COMPLETE_SELECTDATA_OPTS,
|
||||
TAB_COMPLETE_MAX_INDEX
|
||||
};
|
||||
|
||||
@@ -1311,28 +1291,33 @@ command_name_generator(const char *text, int state)
|
||||
{
|
||||
const char *name, **names[TAB_COMPLETE_MAX_INDEX];
|
||||
const char *base_commands[] = {
|
||||
"accheck", "activity", "add", "allow", "burst",
|
||||
"accheck", "activity", "add", "allow", "authdata", "burst",
|
||||
"clients", "cmdaccheck", "cmdallow", "cmddeny", "cyclelogs", "delete",
|
||||
"deny", "dns", "dump", "exit", "help", "keygen", "local", "makestep",
|
||||
"manual", "maxdelay", "maxdelaydevratio", "maxdelayratio", "maxpoll",
|
||||
"maxupdateskew", "minpoll", "minstratum", "ntpdata", "offline", "online", "onoffline",
|
||||
"polltarget", "quit", "refresh", "rekey", "reselect", "reselectdist", "reset",
|
||||
"retries", "rtcdata", "serverstats", "settime", "shutdown", "smoothing",
|
||||
"polltarget", "quit", "refresh", "rekey", "reload", "reselect", "reselectdist", "reset",
|
||||
"retries", "rtcdata", "selectdata", "serverstats", "settime", "shutdown", "smoothing",
|
||||
"smoothtime", "sourcename", "sources", "sourcestats",
|
||||
"timeout", "tracking", "trimrtc", "waitsync", "writertc",
|
||||
NULL
|
||||
};
|
||||
const char *add_options[] = { "peer", "pool", "server", NULL };
|
||||
const char *manual_options[] = { "on", "off", "delete", "list", "reset", NULL };
|
||||
const char *sources_options[] = { "-a", "-v", NULL };
|
||||
const char *sourcestats_options[] = { "-a", "-v", NULL };
|
||||
const char *reset_options[] = { "sources", NULL };
|
||||
const char *reload_options[] = { "sources", NULL };
|
||||
const char *common_source_options[] = { "-a", "-v", NULL };
|
||||
static int list_index, len;
|
||||
|
||||
names[TAB_COMPLETE_BASE_CMDS] = base_commands;
|
||||
names[TAB_COMPLETE_ADD_OPTS] = add_options;
|
||||
names[TAB_COMPLETE_MANUAL_OPTS] = manual_options;
|
||||
names[TAB_COMPLETE_SOURCES_OPTS] = sources_options;
|
||||
names[TAB_COMPLETE_SOURCESTATS_OPTS] = sourcestats_options;
|
||||
names[TAB_COMPLETE_RELOAD_OPTS] = reload_options;
|
||||
names[TAB_COMPLETE_RESET_OPTS] = reset_options;
|
||||
names[TAB_COMPLETE_AUTHDATA_OPTS] = common_source_options;
|
||||
names[TAB_COMPLETE_SELECTDATA_OPTS] = common_source_options;
|
||||
names[TAB_COMPLETE_SOURCES_OPTS] = common_source_options;
|
||||
names[TAB_COMPLETE_SOURCESTATS_OPTS] = common_source_options;
|
||||
|
||||
if (!state) {
|
||||
list_index = 0;
|
||||
@@ -1360,8 +1345,16 @@ command_name_completion(const char *text, int start, int end)
|
||||
|
||||
if (!strcmp(first, "add ")) {
|
||||
tab_complete_index = TAB_COMPLETE_ADD_OPTS;
|
||||
} else if (!strcmp(first, "authdata ")) {
|
||||
tab_complete_index = TAB_COMPLETE_AUTHDATA_OPTS;
|
||||
} else if (!strcmp(first, "manual ")) {
|
||||
tab_complete_index = TAB_COMPLETE_MANUAL_OPTS;
|
||||
} else if (!strcmp(first, "reload ")) {
|
||||
tab_complete_index = TAB_COMPLETE_RELOAD_OPTS;
|
||||
} else if (!strcmp(first, "reset ")) {
|
||||
tab_complete_index = TAB_COMPLETE_RESET_OPTS;
|
||||
} else if (!strcmp(first, "selectdata ")) {
|
||||
tab_complete_index = TAB_COMPLETE_SELECTDATA_OPTS;
|
||||
} else if (!strcmp(first, "sources ")) {
|
||||
tab_complete_index = TAB_COMPLETE_SOURCES_OPTS;
|
||||
} else if (!strcmp(first, "sourcestats ")) {
|
||||
@@ -2056,7 +2049,7 @@ get_source_name(IPAddr *ip_addr, char *buf, int size)
|
||||
UTI_IPHostToNetwork(ip_addr, &request.data.ntp_source_name.ip_addr);
|
||||
if (!request_reply(&request, &reply, RPY_NTP_SOURCE_NAME, 0) ||
|
||||
reply.data.ntp_source_name.name[sizeof (reply.data.ntp_source_name.name) - 1] != '\0' ||
|
||||
snprintf(buf, size, "%s", reply.data.ntp_source_name.name) >= size)
|
||||
snprintf(buf, size, "%s", (char *)reply.data.ntp_source_name.name) >= size)
|
||||
return 0;
|
||||
|
||||
/* Make sure the name is printable */
|
||||
@@ -2358,6 +2351,91 @@ process_cmd_tracking(char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_authdata(char *line)
|
||||
{
|
||||
CMD_Request request;
|
||||
CMD_Reply reply;
|
||||
IPAddr ip_addr;
|
||||
uint32_t i, source_mode, n_sources;
|
||||
int all, verbose;
|
||||
const char *mode_str;
|
||||
char name[256];
|
||||
|
||||
parse_sources_options(line, &all, &verbose);
|
||||
|
||||
request.command = htons(REQ_N_SOURCES);
|
||||
if (!request_reply(&request, &reply, RPY_N_SOURCES, 0))
|
||||
return 0;
|
||||
|
||||
n_sources = ntohl(reply.data.n_sources.n_sources);
|
||||
|
||||
if (verbose) {
|
||||
printf( " .- Auth. mechanism (NTS, SK - symmetric key)\n");
|
||||
printf( " | Key length -. Cookie length (bytes) -.\n");
|
||||
printf( " | (bits) | Num. of cookies --. |\n");
|
||||
printf( " | | Key est. attempts | |\n");
|
||||
printf( " | | | | |\n");
|
||||
}
|
||||
|
||||
print_header("Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen");
|
||||
|
||||
/* "NNNNNNNNNNNNNNNNNNNNNNNNNNN MMMM KKKKK AAAA LLLL LLLL AAAA NNNN CCCC LLLL" */
|
||||
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
request.command = htons(REQ_SOURCE_DATA);
|
||||
request.data.source_data.index = htonl(i);
|
||||
if (!request_reply(&request, &reply, RPY_SOURCE_DATA, 0))
|
||||
return 0;
|
||||
|
||||
source_mode = ntohs(reply.data.source_data.mode);
|
||||
if (source_mode != RPY_SD_MD_CLIENT && source_mode != RPY_SD_MD_PEER)
|
||||
continue;
|
||||
|
||||
UTI_IPNetworkToHost(&reply.data.source_data.ip_addr, &ip_addr);
|
||||
if (!all && ip_addr.family == IPADDR_ID)
|
||||
continue;
|
||||
|
||||
request.command = htons(REQ_AUTH_DATA);
|
||||
request.data.auth_data.ip_addr = reply.data.source_data.ip_addr;
|
||||
if (!request_reply(&request, &reply, RPY_AUTH_DATA, 0))
|
||||
return 0;
|
||||
|
||||
format_name(name, sizeof (name), 25, 0, 0, 1, &ip_addr);
|
||||
|
||||
switch (ntohs(reply.data.auth_data.mode)) {
|
||||
case RPY_AD_MD_NONE:
|
||||
mode_str = "-";
|
||||
break;
|
||||
case RPY_AD_MD_SYMMETRIC:
|
||||
mode_str = "SK";
|
||||
break;
|
||||
case RPY_AD_MD_NTS:
|
||||
mode_str = "NTS";
|
||||
break;
|
||||
default:
|
||||
mode_str = "?";
|
||||
break;
|
||||
}
|
||||
|
||||
print_report("%-27s %4s %5U %4d %4d %I %4d %4d %4d %4d\n",
|
||||
name, mode_str,
|
||||
(unsigned long)ntohl(reply.data.auth_data.key_id),
|
||||
ntohs(reply.data.auth_data.key_type),
|
||||
ntohs(reply.data.auth_data.key_length),
|
||||
(unsigned long)ntohl(reply.data.auth_data.last_ke_ago),
|
||||
ntohs(reply.data.auth_data.ke_attempts),
|
||||
ntohs(reply.data.auth_data.nak),
|
||||
ntohs(reply.data.auth_data.cookies),
|
||||
ntohs(reply.data.auth_data.cookie_length),
|
||||
REPORT_END);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_ntpdata(char *line)
|
||||
{
|
||||
@@ -2474,6 +2552,81 @@ process_cmd_ntpdata(char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_selectdata(char *line)
|
||||
{
|
||||
CMD_Request request;
|
||||
CMD_Reply reply;
|
||||
uint32_t i, n_sources;
|
||||
int all, verbose, conf_options, eff_options;
|
||||
char name[256];
|
||||
IPAddr ip_addr;
|
||||
|
||||
parse_sources_options(line, &all, &verbose);
|
||||
|
||||
request.command = htons(REQ_N_SOURCES);
|
||||
if (!request_reply(&request, &reply, RPY_N_SOURCES, 0))
|
||||
return 0;
|
||||
|
||||
n_sources = ntohl(reply.data.n_sources.n_sources);
|
||||
|
||||
if (verbose) {
|
||||
printf( " .-- State: N - noselect, M - missing samples, d/D - large distance,\n");
|
||||
printf( " / ~ - jittery, w/W - waits for others, T - not trusted,\n");
|
||||
printf( "| x - falseticker, P - not preferred, U - waits for update,\n");
|
||||
printf( "| S - stale, O - orphan, + - combined, * - best.\n");
|
||||
printf( "| Effective options ------. (N - noselect, P - prefer\n");
|
||||
printf( "| Configured options -. \\ T - trust, R - require)\n");
|
||||
printf( "| Auth. enabled (Y/N) -. \\ \\ Offset interval --.\n");
|
||||
printf( "| | | | |\n");
|
||||
}
|
||||
|
||||
print_header("S Name/IP Address Auth COpts EOpts Last Score Interval ");
|
||||
|
||||
/* "S NNNNNNNNNNNNNNNNNNNNNNNNN A OOOO- OOOO- LLLL SSSSS LLLLLLL LLLLLLL" */
|
||||
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
request.command = htons(REQ_SELECT_DATA);
|
||||
request.data.source_data.index = htonl(i);
|
||||
if (!request_reply(&request, &reply, RPY_SELECT_DATA, 0))
|
||||
return 0;
|
||||
|
||||
UTI_IPNetworkToHost(&reply.data.select_data.ip_addr, &ip_addr);
|
||||
if (!all && ip_addr.family == IPADDR_ID)
|
||||
continue;
|
||||
|
||||
format_name(name, sizeof (name), 25, ip_addr.family == IPADDR_UNSPEC,
|
||||
ntohl(reply.data.select_data.ref_id), 1, &ip_addr);
|
||||
|
||||
conf_options = ntohs(reply.data.select_data.conf_options);
|
||||
eff_options = ntohs(reply.data.select_data.eff_options);
|
||||
|
||||
print_report("%c %-25s %c %c%c%c%c%c %c%c%c%c%c %I %5.1f %+S %+S\n",
|
||||
reply.data.select_data.state_char,
|
||||
name,
|
||||
reply.data.select_data.authentication ? 'Y' : 'N',
|
||||
conf_options & RPY_SD_OPTION_NOSELECT ? 'N' : '-',
|
||||
conf_options & RPY_SD_OPTION_PREFER ? 'P' : '-',
|
||||
conf_options & RPY_SD_OPTION_TRUST ? 'T' : '-',
|
||||
conf_options & RPY_SD_OPTION_REQUIRE ? 'R' : '-',
|
||||
'-',
|
||||
eff_options & RPY_SD_OPTION_NOSELECT ? 'N' : '-',
|
||||
eff_options & RPY_SD_OPTION_PREFER ? 'P' : '-',
|
||||
eff_options & RPY_SD_OPTION_TRUST ? 'T' : '-',
|
||||
eff_options & RPY_SD_OPTION_REQUIRE ? 'R' : '-',
|
||||
'-',
|
||||
(unsigned long)ntohl(reply.data.select_data.last_sample_ago),
|
||||
UTI_FloatNetworkToHost(reply.data.select_data.score),
|
||||
UTI_FloatNetworkToHost(reply.data.select_data.lo_limit),
|
||||
UTI_FloatNetworkToHost(reply.data.select_data.hi_limit),
|
||||
REPORT_END);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_serverstats(char *line)
|
||||
{
|
||||
@@ -2481,19 +2634,25 @@ process_cmd_serverstats(char *line)
|
||||
CMD_Reply reply;
|
||||
|
||||
request.command = htons(REQ_SERVER_STATS);
|
||||
if (!request_reply(&request, &reply, RPY_SERVER_STATS, 0))
|
||||
if (!request_reply(&request, &reply, RPY_SERVER_STATS2, 0))
|
||||
return 0;
|
||||
|
||||
print_report("NTP packets received : %U\n"
|
||||
"NTP packets dropped : %U\n"
|
||||
"Command packets received : %U\n"
|
||||
"Command packets dropped : %U\n"
|
||||
"Client log records dropped : %U\n",
|
||||
"Client log records dropped : %U\n"
|
||||
"NTS-KE connections accepted: %U\n"
|
||||
"NTS-KE connections dropped : %U\n"
|
||||
"Authenticated NTP packets : %U\n",
|
||||
(unsigned long)ntohl(reply.data.server_stats.ntp_hits),
|
||||
(unsigned long)ntohl(reply.data.server_stats.ntp_drops),
|
||||
(unsigned long)ntohl(reply.data.server_stats.cmd_hits),
|
||||
(unsigned long)ntohl(reply.data.server_stats.cmd_drops),
|
||||
(unsigned long)ntohl(reply.data.server_stats.log_drops),
|
||||
(unsigned long)ntohl(reply.data.server_stats.nke_hits),
|
||||
(unsigned long)ntohl(reply.data.server_stats.nke_drops),
|
||||
(unsigned long)ntohl(reply.data.server_stats.ntp_auth_hits),
|
||||
REPORT_END);
|
||||
|
||||
return 1;
|
||||
@@ -2591,20 +2750,46 @@ process_cmd_clients(char *line)
|
||||
CMD_Request request;
|
||||
CMD_Reply reply;
|
||||
IPAddr ip;
|
||||
uint32_t i, n_clients, next_index, n_indices;
|
||||
uint32_t i, n_clients, next_index, n_indices, min_hits, reset;
|
||||
RPY_ClientAccesses_Client *client;
|
||||
char name[50];
|
||||
char header[80], name[50], *opt, *arg;
|
||||
int nke;
|
||||
|
||||
next_index = 0;
|
||||
min_hits = 0;
|
||||
reset = 0;
|
||||
nke = 0;
|
||||
|
||||
print_header("Hostname NTP Drop Int IntL Last Cmd Drop Int Last");
|
||||
while (*line) {
|
||||
opt = line;
|
||||
line = CPS_SplitWord(line);
|
||||
if (strcmp(opt, "-k") == 0) {
|
||||
nke = 1;
|
||||
} else if (strcmp(opt, "-p") == 0) {
|
||||
arg = line;
|
||||
line = CPS_SplitWord(line);
|
||||
if (sscanf(arg, "%"SCNu32, &min_hits) != 1) {
|
||||
LOG(LOGS_ERR, "Invalid syntax for clients command");
|
||||
return 0;
|
||||
}
|
||||
} else if (strcmp(opt, "-r") == 0) {
|
||||
reset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(header, sizeof (header),
|
||||
"Hostname NTP Drop Int IntL Last %6s Drop Int Last",
|
||||
nke ? "NTS-KE" : "Cmd");
|
||||
print_header(header);
|
||||
|
||||
while (1) {
|
||||
request.command = htons(REQ_CLIENT_ACCESSES_BY_INDEX2);
|
||||
request.command = htons(REQ_CLIENT_ACCESSES_BY_INDEX3);
|
||||
request.data.client_accesses_by_index.first_index = htonl(next_index);
|
||||
request.data.client_accesses_by_index.n_clients = htonl(MAX_CLIENT_ACCESSES);
|
||||
request.data.client_accesses_by_index.min_hits = htonl(min_hits);
|
||||
request.data.client_accesses_by_index.reset = htonl(reset);
|
||||
|
||||
if (!request_reply(&request, &reply, RPY_CLIENT_ACCESSES_BY_INDEX2, 0))
|
||||
if (!request_reply(&request, &reply, RPY_CLIENT_ACCESSES_BY_INDEX3, 0))
|
||||
return 0;
|
||||
|
||||
n_clients = ntohl(reply.data.client_accesses_by_index.n_clients);
|
||||
@@ -2629,10 +2814,11 @@ process_cmd_clients(char *line)
|
||||
client->ntp_interval,
|
||||
client->ntp_timeout_interval,
|
||||
(unsigned long)ntohl(client->last_ntp_hit_ago),
|
||||
(unsigned long)ntohl(client->cmd_hits),
|
||||
(unsigned long)ntohl(client->cmd_drops),
|
||||
client->cmd_interval,
|
||||
(unsigned long)ntohl(client->last_cmd_hit_ago),
|
||||
(unsigned long)ntohl(nke ? client->nke_hits : client->cmd_hits),
|
||||
(unsigned long)ntohl(nke ? client->nke_drops : client->cmd_drops),
|
||||
nke ? client->nke_interval : client->cmd_interval,
|
||||
(unsigned long)ntohl(nke ? client->last_nke_hit_ago :
|
||||
client->last_cmd_hit_ago),
|
||||
REPORT_END);
|
||||
}
|
||||
|
||||
@@ -2836,10 +3022,32 @@ process_cmd_shutdown(CMD_Request *msg, char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
static int
|
||||
process_cmd_reload(CMD_Request *msg, char *line)
|
||||
{
|
||||
if (!strcmp(line, "sources")) {
|
||||
msg->command = htons(REQ_RELOAD_SOURCES);
|
||||
} else {
|
||||
LOG(LOGS_ERR, "Invalid syntax for reload command");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_reset(CMD_Request *msg, char *line)
|
||||
{
|
||||
msg->command = htons(REQ_RESET);
|
||||
if (!strcmp(line, "sources")) {
|
||||
msg->command = htons(REQ_RESET_SOURCES);
|
||||
} else {
|
||||
LOG(LOGS_ERR, "Invalid syntax for reset command");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -2959,26 +3167,35 @@ process_cmd_retries(const char *line)
|
||||
static int
|
||||
process_cmd_keygen(char *line)
|
||||
{
|
||||
unsigned int i, args, cmac_length, length, id = 1, bits = 160;
|
||||
unsigned char key[512];
|
||||
char type[17];
|
||||
unsigned int i, cmac_length, length, id = 1, bits = 160;
|
||||
const char *type;
|
||||
char *words[3];
|
||||
|
||||
#ifdef FEAT_SECHASH
|
||||
snprintf(type, sizeof (type), "SHA1");
|
||||
type = "SHA1";
|
||||
#else
|
||||
snprintf(type, sizeof (type), "MD5");
|
||||
type = "MD5";
|
||||
#endif
|
||||
|
||||
if (sscanf(line, "%u %16s %u", &id, type, &bits))
|
||||
;
|
||||
args = UTI_SplitString(line, words, 3);
|
||||
if (args >= 2)
|
||||
type = words[1];
|
||||
|
||||
if (args > 3 ||
|
||||
(args >= 1 && sscanf(words[0], "%u", &id) != 1) ||
|
||||
(args >= 3 && sscanf(words[2], "%u", &bits) != 1)) {
|
||||
LOG(LOGS_ERR, "Invalid syntax for keygen command");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CMAC
|
||||
cmac_length = CMC_GetKeyLength(type);
|
||||
cmac_length = CMC_GetKeyLength(UTI_CmacNameToAlgorithm(type));
|
||||
#else
|
||||
cmac_length = 0;
|
||||
#endif
|
||||
|
||||
if (HSH_GetHashId(type) >= 0) {
|
||||
if (HSH_GetHashId(UTI_HashNameToAlgorithm(type)) >= 0) {
|
||||
length = (bits + 7) / 8;
|
||||
} else if (cmac_length > 0) {
|
||||
length = cmac_length;
|
||||
@@ -3038,6 +3255,9 @@ process_line(char *line)
|
||||
} else {
|
||||
do_normal_submit = process_cmd_allow(&tx_message, line);
|
||||
}
|
||||
} else if (!strcmp(command, "authdata")) {
|
||||
do_normal_submit = 0;
|
||||
ret = process_cmd_authdata(line);
|
||||
} else if (!strcmp(command, "burst")) {
|
||||
do_normal_submit = process_cmd_burst(&tx_message, line);
|
||||
} else if (!strcmp(command, "clients")) {
|
||||
@@ -3134,18 +3354,23 @@ process_line(char *line)
|
||||
process_cmd_refresh(&tx_message, line);
|
||||
} else if (!strcmp(command, "rekey")) {
|
||||
process_cmd_rekey(&tx_message, line);
|
||||
} else if (!strcmp(command, "reload")) {
|
||||
do_normal_submit = process_cmd_reload(&tx_message, line);
|
||||
} else if (!strcmp(command, "reselect")) {
|
||||
process_cmd_reselect(&tx_message, line);
|
||||
} else if (!strcmp(command, "reselectdist")) {
|
||||
do_normal_submit = process_cmd_reselectdist(&tx_message, line);
|
||||
} else if (!strcmp(command, "reset")) {
|
||||
process_cmd_reset(&tx_message, line);
|
||||
do_normal_submit = process_cmd_reset(&tx_message, line);
|
||||
} else if (!strcmp(command, "retries")) {
|
||||
ret = process_cmd_retries(line);
|
||||
do_normal_submit = 0;
|
||||
} else if (!strcmp(command, "rtcdata")) {
|
||||
do_normal_submit = 0;
|
||||
ret = process_cmd_rtcreport(line);
|
||||
} else if (!strcmp(command, "selectdata")) {
|
||||
do_normal_submit = 0;
|
||||
ret = process_cmd_selectdata(line);
|
||||
} else if (!strcmp(command, "serverstats")) {
|
||||
do_normal_submit = 0;
|
||||
ret = process_cmd_serverstats(line);
|
||||
@@ -3358,7 +3583,7 @@ main(int argc, char **argv)
|
||||
|
||||
UTI_SetQuitSignalsHandler(signal_handler, 0);
|
||||
|
||||
SCK_Initialise();
|
||||
SCK_Initialise(IPADDR_UNSPEC);
|
||||
server_addresses = get_addresses(hostnames, port);
|
||||
|
||||
if (!open_io())
|
||||
|
||||
335
clientlog.c
335
clientlog.c
@@ -44,20 +44,17 @@
|
||||
#include "util.h"
|
||||
#include "logging.h"
|
||||
|
||||
#define MAX_SERVICES 3
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
uint32_t last_ntp_hit;
|
||||
uint32_t last_cmd_hit;
|
||||
uint32_t ntp_hits;
|
||||
uint32_t cmd_hits;
|
||||
uint16_t ntp_drops;
|
||||
uint16_t cmd_drops;
|
||||
uint16_t ntp_tokens;
|
||||
uint16_t cmd_tokens;
|
||||
int8_t ntp_rate;
|
||||
int8_t cmd_rate;
|
||||
uint32_t last_hit[MAX_SERVICES];
|
||||
uint32_t hits[MAX_SERVICES];
|
||||
uint16_t drops[MAX_SERVICES];
|
||||
uint16_t tokens[MAX_SERVICES];
|
||||
int8_t rate[MAX_SERVICES];
|
||||
int8_t ntp_timeout_rate;
|
||||
uint8_t flags;
|
||||
uint8_t drop_flags;
|
||||
NTP_int64 ntp_rx_ts;
|
||||
NTP_int64 ntp_tx_ts;
|
||||
} Record;
|
||||
@@ -104,15 +101,12 @@ static uint32_t ts_offset;
|
||||
#define MIN_LIMIT_BURST 1
|
||||
#define MAX_LIMIT_BURST 255
|
||||
|
||||
static uint16_t max_ntp_tokens;
|
||||
static uint16_t max_cmd_tokens;
|
||||
static uint16_t ntp_tokens_per_packet;
|
||||
static uint16_t cmd_tokens_per_packet;
|
||||
static uint16_t max_tokens[MAX_SERVICES];
|
||||
static uint16_t tokens_per_hit[MAX_SERVICES];
|
||||
|
||||
/* Reduction of token rates to avoid overflow of 16-bit counters. Negative
|
||||
shift is used for coarse limiting with intervals shorter than -TS_FRAC. */
|
||||
static int ntp_token_shift;
|
||||
static int cmd_token_shift;
|
||||
static int token_shift[MAX_SERVICES];
|
||||
|
||||
/* Rates at which responses are randomly allowed (in log2) when the
|
||||
buckets don't have enough tokens. This is necessary in order to
|
||||
@@ -122,23 +116,18 @@ static int cmd_token_shift;
|
||||
#define MIN_LEAK_RATE 1
|
||||
#define MAX_LEAK_RATE 4
|
||||
|
||||
static int ntp_leak_rate;
|
||||
static int cmd_leak_rate;
|
||||
static int leak_rate[MAX_SERVICES];
|
||||
|
||||
/* Flag indicating whether the last response was dropped */
|
||||
#define FLAG_NTP_DROPPED 0x1
|
||||
|
||||
/* NTP limit interval in log2 */
|
||||
static int ntp_limit_interval;
|
||||
/* Limit intervals in log2 */
|
||||
static int limit_interval[MAX_SERVICES];
|
||||
|
||||
/* Flag indicating whether facility is turned on or not */
|
||||
static int active;
|
||||
|
||||
/* Global statistics */
|
||||
static uint32_t total_ntp_hits;
|
||||
static uint32_t total_cmd_hits;
|
||||
static uint32_t total_ntp_drops;
|
||||
static uint32_t total_cmd_drops;
|
||||
static uint32_t total_hits[MAX_SERVICES];
|
||||
static uint32_t total_drops[MAX_SERVICES];
|
||||
static uint32_t total_ntp_auth_hits;
|
||||
static uint32_t total_record_drops;
|
||||
|
||||
#define NSEC_PER_SEC 1000000000U
|
||||
@@ -161,12 +150,28 @@ compare_ts(uint32_t x, uint32_t y)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
compare_total_hits(Record *x, Record *y)
|
||||
{
|
||||
uint32_t x_hits, y_hits;
|
||||
int i;
|
||||
|
||||
for (i = 0, x_hits = y_hits = 0; i < MAX_SERVICES; i++) {
|
||||
x_hits += x->hits[i];
|
||||
y_hits += y->hits[i];
|
||||
}
|
||||
|
||||
return x_hits > y_hits ? 1 : -1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static Record *
|
||||
get_record(IPAddr *ip)
|
||||
{
|
||||
unsigned int first, i;
|
||||
time_t last_hit, oldest_hit = 0;
|
||||
uint32_t last_hit, oldest_hit = 0;
|
||||
Record *record, *oldest_record;
|
||||
unsigned int first, i, j;
|
||||
|
||||
if (!active || (ip->family != IPADDR_INET4 && ip->family != IPADDR_INET6))
|
||||
return NULL;
|
||||
@@ -184,12 +189,13 @@ get_record(IPAddr *ip)
|
||||
if (record->ip_addr.family == IPADDR_UNSPEC)
|
||||
break;
|
||||
|
||||
last_hit = compare_ts(record->last_ntp_hit, record->last_cmd_hit) > 0 ?
|
||||
record->last_ntp_hit : record->last_cmd_hit;
|
||||
for (j = 0; j < MAX_SERVICES; j++) {
|
||||
if (j == 0 || compare_ts(last_hit, record->last_hit[j]) < 0)
|
||||
last_hit = record->last_hit[j];
|
||||
}
|
||||
|
||||
if (!oldest_record || compare_ts(oldest_hit, last_hit) > 0 ||
|
||||
(oldest_hit == last_hit && record->ntp_hits + record->cmd_hits <
|
||||
oldest_record->ntp_hits + oldest_record->cmd_hits)) {
|
||||
(oldest_hit == last_hit && compare_total_hits(oldest_record, record) > 0)) {
|
||||
oldest_record = record;
|
||||
oldest_hit = last_hit;
|
||||
}
|
||||
@@ -211,14 +217,18 @@ get_record(IPAddr *ip)
|
||||
}
|
||||
|
||||
record->ip_addr = *ip;
|
||||
record->last_ntp_hit = record->last_cmd_hit = INVALID_TS;
|
||||
record->ntp_hits = record->cmd_hits = 0;
|
||||
record->ntp_drops = record->cmd_drops = 0;
|
||||
record->ntp_tokens = max_ntp_tokens;
|
||||
record->cmd_tokens = max_cmd_tokens;
|
||||
record->ntp_rate = record->cmd_rate = INVALID_RATE;
|
||||
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->flags = 0;
|
||||
record->drop_flags = 0;
|
||||
UTI_ZeroNtp64(&record->ntp_rx_ts);
|
||||
UTI_ZeroNtp64(&record->ntp_tx_ts);
|
||||
|
||||
@@ -306,31 +316,43 @@ set_bucket_params(int interval, int burst, uint16_t *max_tokens,
|
||||
void
|
||||
CLG_Initialise(void)
|
||||
{
|
||||
int interval, burst, leak_rate;
|
||||
int i, interval, burst, lrate;
|
||||
|
||||
max_ntp_tokens = max_cmd_tokens = 0;
|
||||
ntp_tokens_per_packet = cmd_tokens_per_packet = 0;
|
||||
ntp_token_shift = cmd_token_shift = 0;
|
||||
ntp_leak_rate = cmd_leak_rate = 0;
|
||||
ntp_limit_interval = MIN_LIMIT_INTERVAL;
|
||||
for (i = 0; i < MAX_SERVICES; i++) {
|
||||
max_tokens[i] = 0;
|
||||
tokens_per_hit[i] = 0;
|
||||
token_shift[i] = 0;
|
||||
leak_rate[i] = 0;
|
||||
limit_interval[i] = MIN_LIMIT_INTERVAL;
|
||||
|
||||
if (CNF_GetNTPRateLimit(&interval, &burst, &leak_rate)) {
|
||||
set_bucket_params(interval, burst, &max_ntp_tokens, &ntp_tokens_per_packet,
|
||||
&ntp_token_shift);
|
||||
ntp_leak_rate = CLAMP(MIN_LEAK_RATE, leak_rate, MAX_LEAK_RATE);
|
||||
ntp_limit_interval = CLAMP(MIN_LIMIT_INTERVAL, interval, MAX_LIMIT_INTERVAL);
|
||||
}
|
||||
switch (i) {
|
||||
case CLG_NTP:
|
||||
if (!CNF_GetNTPRateLimit(&interval, &burst, &lrate))
|
||||
continue;
|
||||
break;
|
||||
case CLG_NTSKE:
|
||||
if (!CNF_GetNtsRateLimit(&interval, &burst, &lrate))
|
||||
continue;
|
||||
break;
|
||||
case CLG_CMDMON:
|
||||
if (!CNF_GetCommandRateLimit(&interval, &burst, &lrate))
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (CNF_GetCommandRateLimit(&interval, &burst, &leak_rate)) {
|
||||
set_bucket_params(interval, burst, &max_cmd_tokens, &cmd_tokens_per_packet,
|
||||
&cmd_token_shift);
|
||||
cmd_leak_rate = CLAMP(MIN_LEAK_RATE, leak_rate, MAX_LEAK_RATE);
|
||||
set_bucket_params(interval, burst, &max_tokens[i], &tokens_per_hit[i], &token_shift[i]);
|
||||
leak_rate[i] = CLAMP(MIN_LEAK_RATE, lrate, MAX_LEAK_RATE);
|
||||
limit_interval[i] = CLAMP(MIN_LIMIT_INTERVAL, interval, MAX_LIMIT_INTERVAL);
|
||||
}
|
||||
|
||||
active = !CNF_GetNoClientLog();
|
||||
if (!active) {
|
||||
if (ntp_leak_rate || cmd_leak_rate)
|
||||
LOG_FATAL("ratelimit cannot be used with noclientlog");
|
||||
for (i = 0; i < MAX_SERVICES; i++) {
|
||||
if (leak_rate[i] != 0)
|
||||
LOG_FATAL("Rate limiting cannot be enabled with noclientlog");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -339,6 +361,7 @@ CLG_Initialise(void)
|
||||
table where two copies exist at the same time. */
|
||||
max_slots = CNF_GetClientLogLimit() / (sizeof (Record) * SLOT_SIZE * 3 / 2);
|
||||
max_slots = CLAMP(MIN_SLOTS, max_slots, MAX_SLOTS);
|
||||
DEBUG_LOG("Max records %u", 1U << ((int)round(log(max_slots) / log(2)) + SLOT_BITS));
|
||||
|
||||
slots = 0;
|
||||
records = NULL;
|
||||
@@ -380,30 +403,33 @@ get_ts_from_timespec(struct timespec *ts)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
update_record(struct timespec *now, uint32_t *last_hit, uint32_t *hits,
|
||||
uint16_t *tokens, uint32_t max_tokens, int token_shift, int8_t *rate)
|
||||
update_record(CLG_Service service, Record *record, struct timespec *now)
|
||||
{
|
||||
uint32_t interval, now_ts, prev_hit, new_tokens;
|
||||
int interval2;
|
||||
uint32_t interval, now_ts, prev_hit, tokens;
|
||||
int interval2, tshift, mtokens;
|
||||
int8_t *rate;
|
||||
|
||||
now_ts = get_ts_from_timespec(now);
|
||||
|
||||
prev_hit = *last_hit;
|
||||
*last_hit = now_ts;
|
||||
(*hits)++;
|
||||
prev_hit = record->last_hit[service];
|
||||
record->last_hit[service] = now_ts;
|
||||
record->hits[service]++;
|
||||
|
||||
interval = now_ts - prev_hit;
|
||||
|
||||
if (prev_hit == INVALID_TS || (int32_t)interval < 0)
|
||||
return;
|
||||
|
||||
if (token_shift >= 0)
|
||||
new_tokens = (now_ts >> token_shift) - (prev_hit >> token_shift);
|
||||
else if (now_ts - prev_hit > max_tokens)
|
||||
new_tokens = max_tokens;
|
||||
tshift = token_shift[service];
|
||||
mtokens = max_tokens[service];
|
||||
|
||||
if (tshift >= 0)
|
||||
tokens = (now_ts >> tshift) - (prev_hit >> tshift);
|
||||
else if (now_ts - prev_hit > mtokens)
|
||||
tokens = mtokens;
|
||||
else
|
||||
new_tokens = (now_ts - prev_hit) << -token_shift;
|
||||
*tokens = MIN(*tokens + new_tokens, max_tokens);
|
||||
tokens = (now_ts - prev_hit) << -tshift;
|
||||
record->tokens[service] = MIN(record->tokens[service] + tokens, mtokens);
|
||||
|
||||
/* Convert the interval to scaled and rounded log2 */
|
||||
if (interval) {
|
||||
@@ -418,6 +444,11 @@ update_record(struct timespec *now, uint32_t *last_hit, uint32_t *hits,
|
||||
interval2 = -RATE_SCALE * (TS_FRAC + 1);
|
||||
}
|
||||
|
||||
/* For the NTP service, update one of the two rates depending on whether
|
||||
the previous request of the client had a reply or it timed out */
|
||||
rate = service == CLG_NTP && record->drop_flags & (1U << service) ?
|
||||
&record->ntp_timeout_rate : &record->rate[service];
|
||||
|
||||
/* Update the rate in a rough approximation of exponential moving average */
|
||||
if (*rate == INVALID_RATE) {
|
||||
*rate = -interval2;
|
||||
@@ -457,50 +488,33 @@ CLG_GetClientIndex(IPAddr *client)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CLG_LogNTPAccess(IPAddr *client, struct timespec *now)
|
||||
static void
|
||||
check_service_number(CLG_Service service)
|
||||
{
|
||||
Record *record;
|
||||
|
||||
total_ntp_hits++;
|
||||
|
||||
record = get_record(client);
|
||||
if (record == NULL)
|
||||
return -1;
|
||||
|
||||
/* Update one of the two rates depending on whether the previous request
|
||||
of the client had a reply or it timed out */
|
||||
update_record(now, &record->last_ntp_hit, &record->ntp_hits,
|
||||
&record->ntp_tokens, max_ntp_tokens, ntp_token_shift,
|
||||
record->flags & FLAG_NTP_DROPPED ?
|
||||
&record->ntp_timeout_rate : &record->ntp_rate);
|
||||
|
||||
DEBUG_LOG("NTP hits %"PRIu32" rate %d trate %d tokens %d",
|
||||
record->ntp_hits, record->ntp_rate, record->ntp_timeout_rate,
|
||||
record->ntp_tokens);
|
||||
|
||||
return get_index(record);
|
||||
assert(service >= 0 && service <= MAX_SERVICES);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CLG_LogCommandAccess(IPAddr *client, struct timespec *now)
|
||||
CLG_LogServiceAccess(CLG_Service service, IPAddr *client, struct timespec *now)
|
||||
{
|
||||
Record *record;
|
||||
|
||||
total_cmd_hits++;
|
||||
check_service_number(service);
|
||||
|
||||
total_hits[service]++;
|
||||
|
||||
record = get_record(client);
|
||||
if (record == NULL)
|
||||
return -1;
|
||||
|
||||
update_record(now, &record->last_cmd_hit, &record->cmd_hits,
|
||||
&record->cmd_tokens, max_cmd_tokens, cmd_token_shift,
|
||||
&record->cmd_rate);
|
||||
update_record(service, record, now);
|
||||
|
||||
DEBUG_LOG("Cmd hits %"PRIu32" rate %d tokens %d",
|
||||
record->cmd_hits, record->cmd_rate, record->cmd_tokens);
|
||||
DEBUG_LOG("service %d hits %"PRIu32" rate %d trate %d tokens %d",
|
||||
(int)service, record->hits[service], record->rate[service],
|
||||
service == CLG_NTP ? record->ntp_timeout_rate : INVALID_RATE,
|
||||
record->tokens[service]);
|
||||
|
||||
return get_index(record);
|
||||
}
|
||||
@@ -530,71 +544,53 @@ limit_response_random(int leak_rate)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CLG_LimitNTPResponseRate(int index)
|
||||
CLG_LimitServiceRate(CLG_Service service, int index)
|
||||
{
|
||||
Record *record;
|
||||
int drop;
|
||||
|
||||
if (!ntp_tokens_per_packet)
|
||||
check_service_number(service);
|
||||
|
||||
if (tokens_per_hit[service] == 0)
|
||||
return 0;
|
||||
|
||||
record = ARR_GetElement(records, index);
|
||||
record->flags &= ~FLAG_NTP_DROPPED;
|
||||
record->drop_flags &= ~(1U << service);
|
||||
|
||||
if (record->ntp_tokens >= ntp_tokens_per_packet) {
|
||||
record->ntp_tokens -= ntp_tokens_per_packet;
|
||||
if (record->tokens[service] >= tokens_per_hit[service]) {
|
||||
record->tokens[service] -= tokens_per_hit[service];
|
||||
return 0;
|
||||
}
|
||||
|
||||
drop = limit_response_random(ntp_leak_rate);
|
||||
drop = limit_response_random(leak_rate[service]);
|
||||
|
||||
/* Poorly implemented clients may send new requests at even a higher rate
|
||||
/* Poorly implemented NTP clients can send requests at a higher rate
|
||||
when they are not getting replies. If the request rate seems to be more
|
||||
than twice as much as when replies are sent, give up on rate limiting to
|
||||
reduce the amount of traffic. Invert the sense of the leak to respond to
|
||||
most of the requests, but still keep the estimated rate updated. */
|
||||
if (record->ntp_timeout_rate != INVALID_RATE &&
|
||||
record->ntp_timeout_rate > record->ntp_rate + RATE_SCALE)
|
||||
if (service == CLG_NTP && record->ntp_timeout_rate != INVALID_RATE &&
|
||||
record->ntp_timeout_rate > record->rate[service] + RATE_SCALE)
|
||||
drop = !drop;
|
||||
|
||||
if (!drop) {
|
||||
record->ntp_tokens = 0;
|
||||
record->tokens[service] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
record->flags |= FLAG_NTP_DROPPED;
|
||||
record->ntp_drops++;
|
||||
total_ntp_drops++;
|
||||
record->drop_flags |= 1U << service;
|
||||
record->drops[service]++;
|
||||
total_drops[service]++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CLG_LimitCommandResponseRate(int index)
|
||||
void
|
||||
CLG_LogAuthNtpRequest(void)
|
||||
{
|
||||
Record *record;
|
||||
|
||||
if (!cmd_tokens_per_packet)
|
||||
return 0;
|
||||
|
||||
record = ARR_GetElement(records, index);
|
||||
|
||||
if (record->cmd_tokens >= cmd_tokens_per_packet) {
|
||||
record->cmd_tokens -= cmd_tokens_per_packet;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!limit_response_random(cmd_leak_rate)) {
|
||||
record->cmd_tokens = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
record->cmd_drops++;
|
||||
total_cmd_drops++;
|
||||
|
||||
return 1;
|
||||
total_ntp_auth_hits++;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -614,7 +610,7 @@ void CLG_GetNtpTimestamps(int index, NTP_int64 **rx_ts, NTP_int64 **tx_ts)
|
||||
int
|
||||
CLG_GetNtpMinPoll(void)
|
||||
{
|
||||
return ntp_limit_interval;
|
||||
return limit_interval[CLG_NTP];
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -653,10 +649,12 @@ static uint32_t get_last_ago(uint32_t x, uint32_t y)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, struct timespec *now)
|
||||
CLG_GetClientAccessReportByIndex(int index, int reset, uint32_t min_hits,
|
||||
RPT_ClientAccessByIndex_Report *report, struct timespec *now)
|
||||
{
|
||||
Record *record;
|
||||
uint32_t now_ts;
|
||||
int i, r;
|
||||
|
||||
if (!active || index < 0 || index >= ARR_GetSize(records))
|
||||
return 0;
|
||||
@@ -666,20 +664,44 @@ CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *repo
|
||||
if (record->ip_addr.family == IPADDR_UNSPEC)
|
||||
return 0;
|
||||
|
||||
now_ts = get_ts_from_timespec(now);
|
||||
if (min_hits == 0) {
|
||||
r = 1;
|
||||
} else {
|
||||
for (i = r = 0; i < MAX_SERVICES; i++) {
|
||||
if (record->hits[i] >= min_hits) {
|
||||
r = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
report->ip_addr = record->ip_addr;
|
||||
report->ntp_hits = record->ntp_hits;
|
||||
report->cmd_hits = record->cmd_hits;
|
||||
report->ntp_drops = record->ntp_drops;
|
||||
report->cmd_drops = record->cmd_drops;
|
||||
report->ntp_interval = get_interval(record->ntp_rate);
|
||||
report->cmd_interval = get_interval(record->cmd_rate);
|
||||
report->ntp_timeout_interval = get_interval(record->ntp_timeout_rate);
|
||||
report->last_ntp_hit_ago = get_last_ago(now_ts, record->last_ntp_hit);
|
||||
report->last_cmd_hit_ago = get_last_ago(now_ts, record->last_cmd_hit);
|
||||
if (r) {
|
||||
now_ts = get_ts_from_timespec(now);
|
||||
|
||||
return 1;
|
||||
report->ip_addr = record->ip_addr;
|
||||
report->ntp_hits = record->hits[CLG_NTP];
|
||||
report->nke_hits = record->hits[CLG_NTSKE];
|
||||
report->cmd_hits = record->hits[CLG_CMDMON];
|
||||
report->ntp_drops = record->drops[CLG_NTP];
|
||||
report->nke_drops = record->drops[CLG_NTSKE];
|
||||
report->cmd_drops = record->drops[CLG_CMDMON];
|
||||
report->ntp_interval = get_interval(record->rate[CLG_NTP]);
|
||||
report->nke_interval = get_interval(record->rate[CLG_NTSKE]);
|
||||
report->cmd_interval = get_interval(record->rate[CLG_CMDMON]);
|
||||
report->ntp_timeout_interval = get_interval(record->ntp_timeout_rate);
|
||||
report->last_ntp_hit_ago = get_last_ago(now_ts, record->last_hit[CLG_NTP]);
|
||||
report->last_nke_hit_ago = get_last_ago(now_ts, record->last_hit[CLG_NTSKE]);
|
||||
report->last_cmd_hit_ago = get_last_ago(now_ts, record->last_hit[CLG_CMDMON]);
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
for (i = 0; i < MAX_SERVICES; i++) {
|
||||
record->hits[i] = 0;
|
||||
record->drops[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -687,9 +709,12 @@ CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *repo
|
||||
void
|
||||
CLG_GetServerStatsReport(RPT_ServerStatsReport *report)
|
||||
{
|
||||
report->ntp_hits = total_ntp_hits;
|
||||
report->cmd_hits = total_cmd_hits;
|
||||
report->ntp_drops = total_ntp_drops;
|
||||
report->cmd_drops = total_cmd_drops;
|
||||
report->ntp_hits = total_hits[CLG_NTP];
|
||||
report->nke_hits = total_hits[CLG_NTSKE];
|
||||
report->cmd_hits = total_hits[CLG_CMDMON];
|
||||
report->ntp_drops = total_drops[CLG_NTP];
|
||||
report->nke_drops = total_drops[CLG_NTSKE];
|
||||
report->cmd_drops = total_drops[CLG_CMDMON];
|
||||
report->log_drops = total_record_drops;
|
||||
report->ntp_auth_hits = total_ntp_auth_hits;
|
||||
}
|
||||
|
||||
17
clientlog.h
17
clientlog.h
@@ -31,20 +31,27 @@
|
||||
#include "sysincl.h"
|
||||
#include "reports.h"
|
||||
|
||||
typedef enum {
|
||||
CLG_NTP = 0,
|
||||
CLG_NTSKE,
|
||||
CLG_CMDMON,
|
||||
} CLG_Service;
|
||||
|
||||
extern void CLG_Initialise(void);
|
||||
extern void CLG_Finalise(void);
|
||||
extern int CLG_GetClientIndex(IPAddr *client);
|
||||
extern int CLG_LogNTPAccess(IPAddr *client, struct timespec *now);
|
||||
extern int CLG_LogCommandAccess(IPAddr *client, struct timespec *now);
|
||||
extern int CLG_LimitNTPResponseRate(int index);
|
||||
extern int CLG_LimitCommandResponseRate(int index);
|
||||
extern int CLG_LogServiceAccess(CLG_Service service, IPAddr *client, struct timespec *now);
|
||||
extern int CLG_LimitServiceRate(CLG_Service service, int index);
|
||||
extern void CLG_LogAuthNtpRequest(void);
|
||||
extern void CLG_GetNtpTimestamps(int index, NTP_int64 **rx_ts, NTP_int64 **tx_ts);
|
||||
extern int CLG_GetNtpMinPoll(void);
|
||||
|
||||
/* And some reporting functions, for use by chronyc. */
|
||||
|
||||
extern int CLG_GetNumberOfIndices(void);
|
||||
extern int CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, struct timespec *now);
|
||||
extern int CLG_GetClientAccessReportByIndex(int index, int reset, uint32_t min_hits,
|
||||
RPT_ClientAccessByIndex_Report *report,
|
||||
struct timespec *now);
|
||||
extern void CLG_GetServerStatsReport(RPT_ServerStatsReport *report);
|
||||
|
||||
#endif /* GOT_CLIENTLOG_H */
|
||||
|
||||
17
cmac.h
17
cmac.h
@@ -28,13 +28,20 @@
|
||||
#ifndef GOT_CMAC_H
|
||||
#define GOT_CMAC_H
|
||||
|
||||
/* Avoid overlapping with the hash enumeration */
|
||||
typedef enum {
|
||||
CMC_INVALID = 0,
|
||||
CMC_AES128 = 13,
|
||||
CMC_AES256 = 14,
|
||||
} CMC_Algorithm;
|
||||
|
||||
typedef struct CMC_Instance_Record *CMC_Instance;
|
||||
|
||||
extern unsigned int CMC_GetKeyLength(const char *cipher);
|
||||
extern CMC_Instance CMC_CreateInstance(const char *cipher, const unsigned char *key,
|
||||
unsigned int length);
|
||||
extern unsigned int CMC_Hash(CMC_Instance inst, const unsigned char *in, unsigned int in_len,
|
||||
unsigned char *out, unsigned int out_len);
|
||||
extern int CMC_GetKeyLength(CMC_Algorithm algorithm);
|
||||
extern CMC_Instance CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key,
|
||||
int length);
|
||||
extern int CMC_Hash(CMC_Instance inst, const void *in, int in_len,
|
||||
unsigned char *out, int out_len);
|
||||
extern void CMC_DestroyInstance(CMC_Instance inst);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -44,12 +44,12 @@ struct CMC_Instance_Record {
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
unsigned int
|
||||
CMC_GetKeyLength(const char *cipher)
|
||||
int
|
||||
CMC_GetKeyLength(CMC_Algorithm algorithm)
|
||||
{
|
||||
if (strcmp(cipher, "AES128") == 0)
|
||||
if (algorithm == CMC_AES128)
|
||||
return AES128_KEY_SIZE;
|
||||
else if (strcmp(cipher, "AES256") == 0)
|
||||
else if (algorithm == CMC_AES256)
|
||||
return AES256_KEY_SIZE;
|
||||
return 0;
|
||||
}
|
||||
@@ -57,11 +57,11 @@ CMC_GetKeyLength(const char *cipher)
|
||||
/* ================================================== */
|
||||
|
||||
CMC_Instance
|
||||
CMC_CreateInstance(const char *cipher, const unsigned char *key, unsigned int length)
|
||||
CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key, int length)
|
||||
{
|
||||
CMC_Instance inst;
|
||||
|
||||
if (length == 0 || length != CMC_GetKeyLength(cipher))
|
||||
if (length <= 0 || length != CMC_GetKeyLength(algorithm))
|
||||
return NULL;
|
||||
|
||||
inst = MallocNew(struct CMC_Instance_Record);
|
||||
@@ -83,10 +83,12 @@ CMC_CreateInstance(const char *cipher, const unsigned char *key, unsigned int le
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
unsigned int
|
||||
CMC_Hash(CMC_Instance inst, const unsigned char *in, unsigned int in_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
int
|
||||
CMC_Hash(CMC_Instance inst, const void *in, int in_len, unsigned char *out, int out_len)
|
||||
{
|
||||
if (in_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
if (out_len > CMAC128_DIGEST_SIZE)
|
||||
out_len = CMAC128_DIGEST_SIZE;
|
||||
|
||||
|
||||
183
cmdmon.c
183
cmdmon.c
@@ -135,7 +135,11 @@ static const char permissions[] = {
|
||||
PERMIT_AUTH, /* ONOFFLINE */
|
||||
PERMIT_AUTH, /* ADD_SOURCE */
|
||||
PERMIT_OPEN, /* NTP_SOURCE_NAME */
|
||||
PERMIT_AUTH, /* RESET */
|
||||
PERMIT_AUTH, /* RESET_SOURCES */
|
||||
PERMIT_AUTH, /* AUTH_DATA */
|
||||
PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX3 */
|
||||
PERMIT_AUTH, /* SELECT_DATA */
|
||||
PERMIT_AUTH, /* RELOAD_SOURCES */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
@@ -153,23 +157,22 @@ static void read_from_cmd_socket(int sock_fd, int event, void *anything);
|
||||
static int
|
||||
open_socket(int family)
|
||||
{
|
||||
const char *local_path, *iface;
|
||||
IPSockAddr local_addr;
|
||||
const char *local_path;
|
||||
int sock_fd, port;
|
||||
|
||||
switch (family) {
|
||||
case IPADDR_INET4:
|
||||
case IPADDR_INET6:
|
||||
port = CNF_GetCommandPort();
|
||||
if (port == 0 || !SCK_IsFamilySupported(family))
|
||||
if (port == 0 || !SCK_IsIpFamilyEnabled(family))
|
||||
return INVALID_SOCK_FD;
|
||||
|
||||
CNF_GetBindCommandAddress(family, &local_addr.ip_addr);
|
||||
if (local_addr.ip_addr.family != family)
|
||||
SCK_GetLoopbackIPAddress(family, &local_addr.ip_addr);
|
||||
local_addr.port = port;
|
||||
iface = CNF_GetBindCommandInterface();
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, &local_addr, SCK_FLAG_RX_DEST_ADDR);
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, &local_addr, iface, SCK_FLAG_RX_DEST_ADDR);
|
||||
if (sock_fd < 0) {
|
||||
LOG(LOGS_ERR, "Could not open command socket on %s",
|
||||
UTI_IPSockAddrToString(&local_addr));
|
||||
@@ -233,22 +236,17 @@ do_size_checks(void)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CAM_Initialise(int family)
|
||||
CAM_Initialise(void)
|
||||
{
|
||||
assert(!initialised);
|
||||
assert(sizeof (permissions) / sizeof (permissions[0]) == N_REQUEST_TYPES);
|
||||
do_size_checks();
|
||||
|
||||
initialised = 1;
|
||||
|
||||
sock_fdu = INVALID_SOCK_FD;
|
||||
sock_fd4 = INVALID_SOCK_FD;
|
||||
sock_fd6 = INVALID_SOCK_FD;
|
||||
|
||||
if (family == IPADDR_UNSPEC || family == IPADDR_INET4)
|
||||
sock_fd4 = open_socket(IPADDR_INET4);
|
||||
|
||||
if (family == IPADDR_UNSPEC || family == IPADDR_INET6)
|
||||
sock_fd6 = open_socket(IPADDR_INET6);
|
||||
sock_fd4 = open_socket(IPADDR_INET4);
|
||||
sock_fd6 = open_socket(IPADDR_INET6);
|
||||
|
||||
access_auth_table = ADF_CreateTable();
|
||||
}
|
||||
@@ -289,7 +287,7 @@ CAM_OpenUnixSocket(void)
|
||||
{
|
||||
/* This is separated from CAM_Initialise() as it needs to be called when
|
||||
the process has already dropped the root privileges */
|
||||
if (CNF_GetBindCommandPath()[0])
|
||||
if (CNF_GetBindCommandPath())
|
||||
sock_fdu = open_socket(IPADDR_UNSPEC);
|
||||
}
|
||||
|
||||
@@ -300,6 +298,11 @@ transmit_reply(int sock_fd, SCK_Message *message)
|
||||
{
|
||||
message->length = PKL_ReplyLength((CMD_Reply *)message->data);
|
||||
|
||||
/* Don't require responses to non-link-local addresses to use the same
|
||||
interface */
|
||||
if (!SCK_IsLinkLocalIPAddress(&message->remote_addr.ip.ip_addr))
|
||||
message->if_index = INVALID_IF_INDEX;
|
||||
|
||||
if (!SCK_SendMessage(sock_fd, message, 0))
|
||||
return;
|
||||
}
|
||||
@@ -599,11 +602,7 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
tx_message->data.source_data.mode = htons(RPY_SD_MD_REF);
|
||||
break;
|
||||
}
|
||||
tx_message->data.source_data.flags =
|
||||
htons((report.sel_options & SRC_SELECT_PREFER ? RPY_SD_FLAG_PREFER : 0) |
|
||||
(report.sel_options & SRC_SELECT_NOSELECT ? RPY_SD_FLAG_NOSELECT : 0) |
|
||||
(report.sel_options & SRC_SELECT_TRUST ? RPY_SD_FLAG_TRUST : 0) |
|
||||
(report.sel_options & SRC_SELECT_REQUIRE ? RPY_SD_FLAG_REQUIRE : 0));
|
||||
tx_message->data.source_data.flags = htons(0);
|
||||
tx_message->data.source_data.reachability = htons(report.reachability);
|
||||
tx_message->data.source_data.since_sample = htonl(report.latest_meas_ago);
|
||||
tx_message->data.source_data.orig_latest_meas = UTI_FloatHostToNetwork(report.orig_latest_meas);
|
||||
@@ -716,7 +715,7 @@ handle_add_source(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
return;
|
||||
}
|
||||
|
||||
port = (unsigned short)(ntohl(rx_message->data.ntp_source.port));
|
||||
port = ntohl(rx_message->data.ntp_source.port);
|
||||
params.minpoll = ntohl(rx_message->data.ntp_source.minpoll);
|
||||
params.maxpoll = ntohl(rx_message->data.ntp_source.maxpoll);
|
||||
params.presend_minpoll = ntohl(rx_message->data.ntp_source.presend_minpoll);
|
||||
@@ -751,7 +750,7 @@ handle_add_source(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_TRUST ? SRC_SELECT_TRUST : 0) |
|
||||
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_REQUIRE ? SRC_SELECT_REQUIRE : 0);
|
||||
|
||||
status = NSR_AddSourceByName(name, port, pool, type, ¶ms);
|
||||
status = NSR_AddSourceByName(name, port, pool, type, ¶ms, NULL);
|
||||
switch (status) {
|
||||
case NSR_Success:
|
||||
break;
|
||||
@@ -780,13 +779,12 @@ handle_add_source(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
handle_del_source(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
NTP_Remote_Address rem_addr;
|
||||
NSR_Status status;
|
||||
IPAddr ip_addr;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.del_source.ip_addr, &rem_addr.ip_addr);
|
||||
rem_addr.port = 0;
|
||||
UTI_IPNetworkToHost(&rx_message->data.del_source.ip_addr, &ip_addr);
|
||||
|
||||
status = NSR_RemoveSource(&rem_addr);
|
||||
status = NSR_RemoveSource(&ip_addr);
|
||||
switch (status) {
|
||||
case NSR_Success:
|
||||
break;
|
||||
@@ -1000,7 +998,7 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
RPT_ClientAccessByIndex_Report report;
|
||||
RPY_ClientAccesses_Client *client;
|
||||
int n_indices;
|
||||
uint32_t i, j, req_first_index, req_n_clients;
|
||||
uint32_t i, j, req_first_index, req_n_clients, req_min_hits, req_reset;
|
||||
struct timespec now;
|
||||
|
||||
SCH_GetLastEventTime(&now, NULL, NULL);
|
||||
@@ -1009,6 +1007,8 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
req_n_clients = ntohl(rx_message->data.client_accesses_by_index.n_clients);
|
||||
if (req_n_clients > MAX_CLIENT_ACCESSES)
|
||||
req_n_clients = MAX_CLIENT_ACCESSES;
|
||||
req_min_hits = ntohl(rx_message->data.client_accesses_by_index.min_hits);
|
||||
req_reset = ntohl(rx_message->data.client_accesses_by_index.reset);
|
||||
|
||||
n_indices = CLG_GetNumberOfIndices();
|
||||
if (n_indices < 0) {
|
||||
@@ -1016,24 +1016,28 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
return;
|
||||
}
|
||||
|
||||
tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX2);
|
||||
tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX3);
|
||||
tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices);
|
||||
|
||||
for (i = req_first_index, j = 0; i < (uint32_t)n_indices && j < req_n_clients; i++) {
|
||||
if (!CLG_GetClientAccessReportByIndex(i, &report, &now))
|
||||
if (!CLG_GetClientAccessReportByIndex(i, req_reset, req_min_hits, &report, &now))
|
||||
continue;
|
||||
|
||||
client = &tx_message->data.client_accesses_by_index.clients[j++];
|
||||
|
||||
UTI_IPHostToNetwork(&report.ip_addr, &client->ip);
|
||||
client->ntp_hits = htonl(report.ntp_hits);
|
||||
client->nke_hits = htonl(report.nke_hits);
|
||||
client->cmd_hits = htonl(report.cmd_hits);
|
||||
client->ntp_drops = htonl(report.ntp_drops);
|
||||
client->nke_drops = htonl(report.nke_drops);
|
||||
client->cmd_drops = htonl(report.cmd_drops);
|
||||
client->ntp_interval = report.ntp_interval;
|
||||
client->nke_interval = report.nke_interval;
|
||||
client->cmd_interval = report.cmd_interval;
|
||||
client->ntp_timeout_interval = report.ntp_timeout_interval;
|
||||
client->last_ntp_hit_ago = htonl(report.last_ntp_hit_ago);
|
||||
client->last_nke_hit_ago = htonl(report.last_nke_hit_ago);
|
||||
client->last_cmd_hit_ago = htonl(report.last_cmd_hit_ago);
|
||||
}
|
||||
|
||||
@@ -1135,12 +1139,15 @@ handle_server_stats(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
RPT_ServerStatsReport report;
|
||||
|
||||
CLG_GetServerStatsReport(&report);
|
||||
tx_message->reply = htons(RPY_SERVER_STATS);
|
||||
tx_message->reply = htons(RPY_SERVER_STATS2);
|
||||
tx_message->data.server_stats.ntp_hits = htonl(report.ntp_hits);
|
||||
tx_message->data.server_stats.nke_hits = htonl(report.nke_hits);
|
||||
tx_message->data.server_stats.cmd_hits = htonl(report.cmd_hits);
|
||||
tx_message->data.server_stats.ntp_drops = htonl(report.ntp_drops);
|
||||
tx_message->data.server_stats.nke_drops = htonl(report.nke_drops);
|
||||
tx_message->data.server_stats.cmd_drops = htonl(report.cmd_drops);
|
||||
tx_message->data.server_stats.log_drops = htonl(report.log_drops);
|
||||
tx_message->data.server_stats.ntp_auth_hits = htonl(report.ntp_auth_hits);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1204,7 +1211,7 @@ handle_ntp_source_name(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
IPAddr addr;
|
||||
char *name;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.ntp_data.ip_addr, &addr);
|
||||
UTI_IPNetworkToHost(&rx_message->data.ntp_source_name.ip_addr, &addr);
|
||||
name = NSR_GetName(&addr);
|
||||
|
||||
if (!name) {
|
||||
@@ -1226,7 +1233,15 @@ handle_ntp_source_name(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_reset(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
handle_reload_sources(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
CNF_ReloadSources();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_reset_sources(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
struct timespec cooked_now, now;
|
||||
|
||||
@@ -1235,6 +1250,84 @@ handle_reset(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
LCL_NotifyExternalTimeStep(&now, &cooked_now, 0.0, 0.0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_auth_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
RPT_AuthReport report;
|
||||
IPAddr ip_addr;
|
||||
|
||||
UTI_IPNetworkToHost(&rx_message->data.auth_data.ip_addr, &ip_addr);
|
||||
|
||||
if (!NSR_GetAuthReport(&ip_addr, &report)) {
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
return;
|
||||
}
|
||||
|
||||
tx_message->reply = htons(RPY_AUTH_DATA);
|
||||
|
||||
switch (report.mode) {
|
||||
case NTP_AUTH_NONE:
|
||||
tx_message->data.auth_data.mode = htons(RPY_AD_MD_NONE);
|
||||
break;
|
||||
case NTP_AUTH_SYMMETRIC:
|
||||
tx_message->data.auth_data.mode = htons(RPY_AD_MD_SYMMETRIC);
|
||||
break;
|
||||
case NTP_AUTH_NTS:
|
||||
tx_message->data.auth_data.mode = htons(RPY_AD_MD_NTS);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
tx_message->data.auth_data.key_type = htons(report.key_type);
|
||||
tx_message->data.auth_data.key_id = htonl(report.key_id);
|
||||
tx_message->data.auth_data.key_length = htons(report.key_length);
|
||||
tx_message->data.auth_data.ke_attempts = htons(report.ke_attempts);
|
||||
tx_message->data.auth_data.last_ke_ago = htonl(report.last_ke_ago);
|
||||
tx_message->data.auth_data.cookies = htons(report.cookies);
|
||||
tx_message->data.auth_data.cookie_length = htons(report.cookie_length);
|
||||
tx_message->data.auth_data.nak = htons(report.nak);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static uint16_t
|
||||
convert_select_options(int options)
|
||||
{
|
||||
return (options & SRC_SELECT_PREFER ? RPY_SD_OPTION_PREFER : 0) |
|
||||
(options & SRC_SELECT_NOSELECT ? RPY_SD_OPTION_NOSELECT : 0) |
|
||||
(options & SRC_SELECT_TRUST ? RPY_SD_OPTION_TRUST : 0) |
|
||||
(options & SRC_SELECT_REQUIRE ? RPY_SD_OPTION_REQUIRE : 0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_select_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
RPT_SelectReport report;
|
||||
|
||||
if (!SRC_GetSelectReport(ntohl(rx_message->data.select_data.index), &report)) {
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
return;
|
||||
}
|
||||
|
||||
tx_message->reply = htons(RPY_SELECT_DATA);
|
||||
|
||||
tx_message->data.select_data.ref_id = htonl(report.ref_id);
|
||||
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.select_data.ip_addr);
|
||||
tx_message->data.select_data.state_char = report.state_char;
|
||||
tx_message->data.select_data.authentication = report.authentication;
|
||||
tx_message->data.select_data.conf_options = htons(convert_select_options(report.conf_options));
|
||||
tx_message->data.select_data.eff_options = htons(convert_select_options(report.eff_options));
|
||||
tx_message->data.select_data.last_sample_ago = htonl(report.last_sample_ago);
|
||||
tx_message->data.select_data.score = UTI_FloatHostToNetwork(report.score);
|
||||
tx_message->data.select_data.hi_limit = UTI_FloatHostToNetwork(report.hi_limit);
|
||||
tx_message->data.select_data.lo_limit = UTI_FloatHostToNetwork(report.lo_limit);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Read a packet and process it */
|
||||
|
||||
@@ -1247,7 +1340,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
IPAddr loopback_addr, remote_ip;
|
||||
int read_length, expected_length;
|
||||
int localhost, allowed, log_index;
|
||||
unsigned short rx_command;
|
||||
uint16_t rx_command;
|
||||
struct timespec now, cooked_now;
|
||||
|
||||
sck_message = SCK_ReceiveMessage(sock_fd, 0);
|
||||
@@ -1305,11 +1398,11 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
return;
|
||||
}
|
||||
|
||||
log_index = CLG_LogCommandAccess(&remote_ip, &cooked_now);
|
||||
log_index = CLG_LogServiceAccess(CLG_CMDMON, &remote_ip, &cooked_now);
|
||||
|
||||
/* Don't reply to all requests from hosts other than localhost if the rate
|
||||
is excessive */
|
||||
if (!localhost && log_index >= 0 && CLG_LimitCommandResponseRate(log_index)) {
|
||||
if (!localhost && log_index >= 0 && CLG_LimitServiceRate(CLG_CMDMON, log_index)) {
|
||||
DEBUG_LOG("Command packet discarded to limit response rate");
|
||||
return;
|
||||
}
|
||||
@@ -1553,7 +1646,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
handle_cyclelogs(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_CLIENT_ACCESSES_BY_INDEX2:
|
||||
case REQ_CLIENT_ACCESSES_BY_INDEX3:
|
||||
handle_client_accesses_by_index(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
@@ -1613,8 +1706,20 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
handle_ntp_source_name(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_RESET:
|
||||
handle_reset(&rx_message, &tx_message);
|
||||
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;
|
||||
|
||||
default:
|
||||
|
||||
2
cmdmon.h
2
cmdmon.h
@@ -29,7 +29,7 @@
|
||||
|
||||
#include "addressing.h"
|
||||
|
||||
extern void CAM_Initialise(int family);
|
||||
extern void CAM_Initialise(void);
|
||||
|
||||
extern void CAM_Finalise(void);
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
if (sscanf(line, "%lf%n", &src->params.offset, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "port")) {
|
||||
if (sscanf(line, "%hu%n", &src->port, &n) != 1)
|
||||
if (sscanf(line, "%d%n", &src->port, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "polltarget")) {
|
||||
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1)
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
unsigned short port;
|
||||
int port;
|
||||
SourceParameters params;
|
||||
} CPS_NTP_Source;
|
||||
|
||||
|
||||
478
conf.c
478
conf.c
@@ -33,8 +33,10 @@
|
||||
#include "conf.h"
|
||||
#include "ntp_sources.h"
|
||||
#include "ntp_core.h"
|
||||
#include "nts_ke.h"
|
||||
#include "refclock.h"
|
||||
#include "cmdmon.h"
|
||||
#include "socket.h"
|
||||
#include "srcparams.h"
|
||||
#include "logging.h"
|
||||
#include "nameserv.h"
|
||||
@@ -42,6 +44,12 @@
|
||||
#include "cmdparse.h"
|
||||
#include "util.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define MAX_LINE_LENGTH 2048
|
||||
#define MAX_CONF_DIRS 10
|
||||
#define MAX_INCLUDE_LEVEL 10
|
||||
|
||||
/* ================================================== */
|
||||
/* Forward prototypes */
|
||||
|
||||
@@ -51,11 +59,13 @@ static int parse_double(char *line, double *result);
|
||||
static int parse_null(char *line);
|
||||
|
||||
static void parse_allow_deny(char *line, ARR_Instance restrictions, int allow);
|
||||
static void parse_authselectmode(char *);
|
||||
static void parse_bindacqaddress(char *);
|
||||
static void parse_bindaddress(char *);
|
||||
static void parse_bindcmdaddress(char *);
|
||||
static void parse_broadcast(char *);
|
||||
static void parse_clientloglimit(char *);
|
||||
static void parse_confdir(char *);
|
||||
static void parse_fallbackdrift(char *);
|
||||
static void parse_hwtimestamp(char *);
|
||||
static void parse_include(char *);
|
||||
@@ -70,12 +80,14 @@ static void parse_ratelimit(char *line, int *enabled, int *interval,
|
||||
int *burst, int *leak);
|
||||
static void parse_refclock(char *);
|
||||
static void parse_smoothtime(char *);
|
||||
static void parse_source(char *line, NTP_Source_Type type, int pool);
|
||||
static void parse_source(char *line, char *type, int fatal);
|
||||
static void parse_sourcedir(char *);
|
||||
static void parse_tempcomp(char *);
|
||||
|
||||
/* ================================================== */
|
||||
/* Configuration variables */
|
||||
|
||||
static int print_config = 0;
|
||||
static int restarted = 0;
|
||||
static char *rtc_device;
|
||||
static int acquisition_port = -1;
|
||||
@@ -89,6 +101,7 @@ static double max_clock_error = 1.0; /* in ppm */
|
||||
static double max_drift = 500000.0; /* in ppm */
|
||||
static double max_slew_rate = 1e6 / 12.0; /* in ppm */
|
||||
|
||||
static SRC_AuthSelectMode authselect_mode = SRC_AUTHSELECT_MIX;
|
||||
static double max_distance = 3.0;
|
||||
static double max_jitter = 1.0;
|
||||
static double reselect_distance = 1e-4;
|
||||
@@ -105,8 +118,8 @@ static int do_log_rtc = 0;
|
||||
static int do_log_refclocks = 0;
|
||||
static int do_log_tempcomp = 0;
|
||||
static int log_banner = 32;
|
||||
static char *logdir;
|
||||
static char *dumpdir;
|
||||
static char *logdir = NULL;
|
||||
static char *dumpdir = NULL;
|
||||
|
||||
static int enable_local=0;
|
||||
static int local_stratum;
|
||||
@@ -180,21 +193,33 @@ static IPAddr bind_acq_address4, bind_acq_address6;
|
||||
the loopback address will be used */
|
||||
static IPAddr bind_cmd_address4, bind_cmd_address6;
|
||||
|
||||
/* Interface names to bind the NTP server, NTP client, and command socket */
|
||||
static char *bind_ntp_iface = NULL;
|
||||
static char *bind_acq_iface = NULL;
|
||||
static char *bind_cmd_iface = NULL;
|
||||
|
||||
/* Path to the Unix domain command socket. */
|
||||
static char *bind_cmd_path;
|
||||
static char *bind_cmd_path = NULL;
|
||||
|
||||
/* Differentiated Services Code Point (DSCP) in transmitted NTP packets */
|
||||
static int ntp_dscp = 0;
|
||||
|
||||
/* Path to Samba (ntp_signd) socket. */
|
||||
static char *ntp_signd_socket = NULL;
|
||||
|
||||
/* Filename to use for storing pid of running chronyd, to prevent multiple
|
||||
* chronyds being started. */
|
||||
static char *pidfile;
|
||||
static char *pidfile = NULL;
|
||||
|
||||
/* Rate limiting parameters */
|
||||
static int ntp_ratelimit_enabled = 0;
|
||||
static int ntp_ratelimit_interval = 3;
|
||||
static int ntp_ratelimit_burst = 8;
|
||||
static int ntp_ratelimit_leak = 2;
|
||||
static int nts_ratelimit_enabled = 0;
|
||||
static int nts_ratelimit_interval = 6;
|
||||
static int nts_ratelimit_burst = 8;
|
||||
static int nts_ratelimit_leak = 2;
|
||||
static int cmd_ratelimit_enabled = 0;
|
||||
static int cmd_ratelimit_interval = -4;
|
||||
static int cmd_ratelimit_burst = 8;
|
||||
@@ -228,7 +253,7 @@ static char *nts_dump_dir = NULL;
|
||||
static char *nts_ntp_server = NULL;
|
||||
static char *nts_server_cert_file = NULL;
|
||||
static char *nts_server_key_file = NULL;
|
||||
static int nts_server_port = 11443;
|
||||
static int nts_server_port = NKE_PORT;
|
||||
static int nts_server_processes = 1;
|
||||
static int nts_server_connections = 100;
|
||||
static int nts_refresh = 2419200; /* 4 weeks */
|
||||
@@ -252,6 +277,10 @@ typedef struct {
|
||||
|
||||
/* Array of NTP_Source */
|
||||
static ARR_Instance ntp_sources;
|
||||
/* Array of (char *) */
|
||||
static ARR_Instance ntp_source_dirs;
|
||||
/* Array of uint32_t corresponding to ntp_sources (for sourcedirs reload) */
|
||||
static ARR_Instance ntp_source_ids;
|
||||
|
||||
/* Array of RefclockParameters */
|
||||
static ARR_Instance refclock_sources;
|
||||
@@ -268,8 +297,7 @@ static ARR_Instance ntp_restrictions;
|
||||
static ARR_Instance cmd_restrictions;
|
||||
|
||||
typedef struct {
|
||||
IPAddr addr;
|
||||
unsigned short port;
|
||||
NTP_Remote_Address addr;
|
||||
int interval;
|
||||
} NTP_Broadcast_Destination;
|
||||
|
||||
@@ -283,6 +311,8 @@ static int line_number;
|
||||
static const char *processed_file;
|
||||
static const char *processed_command;
|
||||
|
||||
static int include_level = 0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
@@ -349,26 +379,31 @@ CNF_Initialise(int r, int client_only)
|
||||
|
||||
init_sources = ARR_CreateInstance(sizeof (IPAddr));
|
||||
ntp_sources = ARR_CreateInstance(sizeof (NTP_Source));
|
||||
ntp_source_dirs = ARR_CreateInstance(sizeof (char *));
|
||||
ntp_source_ids = ARR_CreateInstance(sizeof (uint32_t));
|
||||
refclock_sources = ARR_CreateInstance(sizeof (RefclockParameters));
|
||||
broadcasts = ARR_CreateInstance(sizeof (NTP_Broadcast_Destination));
|
||||
|
||||
ntp_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
|
||||
cmd_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
|
||||
|
||||
dumpdir = Strdup("");
|
||||
logdir = Strdup("");
|
||||
rtc_device = Strdup(DEFAULT_RTC_DEVICE);
|
||||
hwclock_file = Strdup(DEFAULT_HWCLOCK_FILE);
|
||||
user = Strdup(DEFAULT_USER);
|
||||
|
||||
if (client_only) {
|
||||
cmd_port = ntp_port = 0;
|
||||
bind_cmd_path = Strdup("");
|
||||
pidfile = Strdup("");
|
||||
} else {
|
||||
bind_cmd_path = Strdup(DEFAULT_COMMAND_SOCKET);
|
||||
pidfile = Strdup(DEFAULT_PID_FILE);
|
||||
}
|
||||
|
||||
SCK_GetAnyLocalIPAddress(IPADDR_INET4, &bind_address4);
|
||||
SCK_GetAnyLocalIPAddress(IPADDR_INET6, &bind_address6);
|
||||
SCK_GetAnyLocalIPAddress(IPADDR_INET4, &bind_acq_address4);
|
||||
SCK_GetAnyLocalIPAddress(IPADDR_INET6, &bind_acq_address6);
|
||||
SCK_GetLoopbackIPAddress(IPADDR_INET4, &bind_cmd_address4);
|
||||
SCK_GetLoopbackIPAddress(IPADDR_INET6, &bind_cmd_address6);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -384,9 +419,13 @@ CNF_Finalise(void)
|
||||
|
||||
for (i = 0; i < ARR_GetSize(ntp_sources); i++)
|
||||
Free(((NTP_Source *)ARR_GetElement(ntp_sources, i))->params.name);
|
||||
for (i = 0; i < ARR_GetSize(ntp_source_dirs); i++)
|
||||
Free(*(char **)ARR_GetElement(ntp_source_dirs, i));
|
||||
|
||||
ARR_DestroyInstance(init_sources);
|
||||
ARR_DestroyInstance(ntp_sources);
|
||||
ARR_DestroyInstance(ntp_source_dirs);
|
||||
ARR_DestroyInstance(ntp_source_ids);
|
||||
ARR_DestroyInstance(refclock_sources);
|
||||
ARR_DestroyInstance(broadcasts);
|
||||
|
||||
@@ -399,6 +438,9 @@ CNF_Finalise(void)
|
||||
Free(keys_file);
|
||||
Free(leapsec_tz);
|
||||
Free(logdir);
|
||||
Free(bind_ntp_iface);
|
||||
Free(bind_acq_iface);
|
||||
Free(bind_cmd_iface);
|
||||
Free(bind_cmd_path);
|
||||
Free(ntp_signd_socket);
|
||||
Free(pidfile);
|
||||
@@ -417,14 +459,26 @@ CNF_Finalise(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CNF_EnablePrint(void)
|
||||
{
|
||||
print_config = 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Read the configuration file */
|
||||
void
|
||||
CNF_ReadFile(const char *filename)
|
||||
{
|
||||
FILE *in;
|
||||
char line[2048];
|
||||
char line[MAX_LINE_LENGTH + 1];
|
||||
int i;
|
||||
|
||||
include_level++;
|
||||
if (include_level > MAX_INCLUDE_LEVEL)
|
||||
LOG_FATAL("Maximum include level reached");
|
||||
|
||||
in = UTI_OpenFile(NULL, filename, NULL, 'R', 0);
|
||||
|
||||
for (i = 1; fgets(line, sizeof(line), in); i++) {
|
||||
@@ -432,6 +486,8 @@ CNF_ReadFile(const char *filename)
|
||||
}
|
||||
|
||||
fclose(in);
|
||||
|
||||
include_level--;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -446,27 +502,44 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
processed_file = filename;
|
||||
line_number = number;
|
||||
|
||||
/* Detect truncated line */
|
||||
if (strlen(line) >= MAX_LINE_LENGTH)
|
||||
other_parse_error("String too long");
|
||||
|
||||
/* Remove extra white-space and comments */
|
||||
CPS_NormalizeLine(line);
|
||||
|
||||
/* Skip blank lines */
|
||||
if (!*line)
|
||||
if (!*line) {
|
||||
processed_file = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* We have a real line, now try to match commands */
|
||||
processed_command = command = line;
|
||||
p = CPS_SplitWord(line);
|
||||
|
||||
if (print_config && strcasecmp(command, "include") && strcasecmp(command, "confdir"))
|
||||
printf("%s%s%s\n", command, p[0] != '\0' ? " " : "", p);
|
||||
|
||||
if (!strcasecmp(command, "acquisitionport")) {
|
||||
parse_int(p, &acquisition_port);
|
||||
} else if (!strcasecmp(command, "allow")) {
|
||||
parse_allow_deny(p, ntp_restrictions, 1);
|
||||
} else if (!strcasecmp(command, "authselectmode")) {
|
||||
parse_authselectmode(p);
|
||||
} else if (!strcasecmp(command, "bindacqaddress")) {
|
||||
parse_bindacqaddress(p);
|
||||
} else if (!strcasecmp(command, "bindacqdevice")) {
|
||||
parse_string(p, &bind_acq_iface);
|
||||
} else if (!strcasecmp(command, "bindaddress")) {
|
||||
parse_bindaddress(p);
|
||||
} else if (!strcasecmp(command, "bindcmdaddress")) {
|
||||
parse_bindcmdaddress(p);
|
||||
} else if (!strcasecmp(command, "bindcmddevice")) {
|
||||
parse_string(p, &bind_cmd_iface);
|
||||
} else if (!strcasecmp(command, "binddevice")) {
|
||||
parse_string(p, &bind_ntp_iface);
|
||||
} else if (!strcasecmp(command, "broadcast")) {
|
||||
parse_broadcast(p);
|
||||
} else if (!strcasecmp(command, "clientloglimit")) {
|
||||
@@ -482,12 +555,16 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
&cmd_ratelimit_burst, &cmd_ratelimit_leak);
|
||||
} else if (!strcasecmp(command, "combinelimit")) {
|
||||
parse_double(p, &combine_limit);
|
||||
} else if (!strcasecmp(command, "confdir")) {
|
||||
parse_confdir(p);
|
||||
} else if (!strcasecmp(command, "corrtimeratio")) {
|
||||
parse_double(p, &correction_time_ratio);
|
||||
} else if (!strcasecmp(command, "deny")) {
|
||||
parse_allow_deny(p, ntp_restrictions, 0);
|
||||
} else if (!strcasecmp(command, "driftfile")) {
|
||||
parse_string(p, &drift_file);
|
||||
} else if (!strcasecmp(command, "dscp")) {
|
||||
parse_int(p, &ntp_dscp);
|
||||
} else if (!strcasecmp(command, "dumpdir")) {
|
||||
parse_string(p, &dumpdir);
|
||||
} else if (!strcasecmp(command, "dumponexit")) {
|
||||
@@ -556,6 +633,9 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
no_system_cert = parse_null(p);
|
||||
} else if (!strcasecmp(command, "ntpsigndsocket")) {
|
||||
parse_string(p, &ntp_signd_socket);
|
||||
} else if (!strcasecmp(command, "ntsratelimit")) {
|
||||
parse_ratelimit(p, &nts_ratelimit_enabled, &nts_ratelimit_interval,
|
||||
&nts_ratelimit_burst, &nts_ratelimit_leak);
|
||||
} else if (!strcasecmp(command, "ntstrustedcerts")) {
|
||||
parse_string(p, &nts_trusted_cert_file);
|
||||
} else if (!strcasecmp(command, "ntscachedir") ||
|
||||
@@ -576,11 +656,11 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "ntsserverkey")) {
|
||||
parse_string(p, &nts_server_key_file);
|
||||
} else if (!strcasecmp(command, "peer")) {
|
||||
parse_source(p, NTP_PEER, 0);
|
||||
parse_source(p, command, 1);
|
||||
} else if (!strcasecmp(command, "pidfile")) {
|
||||
parse_string(p, &pidfile);
|
||||
} else if (!strcasecmp(command, "pool")) {
|
||||
parse_source(p, NTP_SERVER, 1);
|
||||
parse_source(p, command, 1);
|
||||
} else if (!strcasecmp(command, "port")) {
|
||||
parse_int(p, &ntp_port);
|
||||
} else if (!strcasecmp(command, "ratelimit")) {
|
||||
@@ -603,9 +683,11 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "sched_priority")) {
|
||||
parse_int(p, &sched_priority);
|
||||
} else if (!strcasecmp(command, "server")) {
|
||||
parse_source(p, NTP_SERVER, 0);
|
||||
parse_source(p, command, 1);
|
||||
} else if (!strcasecmp(command, "smoothtime")) {
|
||||
parse_smoothtime(p);
|
||||
} else if (!strcasecmp(command, "sourcedir")) {
|
||||
parse_sourcedir(p);
|
||||
} else if (!strcasecmp(command, "stratumweight")) {
|
||||
parse_double(p, &stratum_weight);
|
||||
} else if (!strcasecmp(command, "tempcomp")) {
|
||||
@@ -618,8 +700,10 @@ 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 command");
|
||||
other_parse_error("Invalid directive");
|
||||
}
|
||||
|
||||
processed_file = processed_command = NULL;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -671,15 +755,31 @@ parse_null(char *line)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_source(char *line, NTP_Source_Type type, int pool)
|
||||
parse_source(char *line, char *type, int fatal)
|
||||
{
|
||||
NTP_Source source;
|
||||
|
||||
source.type = type;
|
||||
source.pool = pool;
|
||||
if (strcasecmp(type, "peer") == 0) {
|
||||
source.type = NTP_PEER;
|
||||
source.pool = 0;
|
||||
} else if (strcasecmp(type, "pool") == 0) {
|
||||
source.type = NTP_SERVER;
|
||||
source.pool = 1;
|
||||
} else if (strcasecmp(type, "server") == 0) {
|
||||
source.type = NTP_SERVER;
|
||||
source.pool = 0;
|
||||
} else {
|
||||
if (fatal)
|
||||
command_parse_error();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Avoid comparing uninitialized data in compare_sources() */
|
||||
memset(&source.params, 0, sizeof (source.params));
|
||||
|
||||
if (!CPS_ParseNTPSourceAdd(line, &source.params)) {
|
||||
command_parse_error();
|
||||
if (fatal)
|
||||
command_parse_error();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -689,6 +789,17 @@ parse_source(char *line, NTP_Source_Type type, int pool)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_sourcedir(char *line)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = Strdup(line);
|
||||
ARR_AppendElement(ntp_source_dirs, &s);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_ratelimit(char *line, int *enabled, int *interval, int *burst, int *leak)
|
||||
{
|
||||
@@ -1141,6 +1252,23 @@ parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_authselectmode(char *line)
|
||||
{
|
||||
if (!strcasecmp(line, "require"))
|
||||
authselect_mode = SRC_AUTHSELECT_REQUIRE;
|
||||
else if (!strcasecmp(line, "prefer"))
|
||||
authselect_mode = SRC_AUTHSELECT_PREFER;
|
||||
else if (!strcasecmp(line, "mix"))
|
||||
authselect_mode = SRC_AUTHSELECT_MIX;
|
||||
else if (!strcasecmp(line, "ignore"))
|
||||
authselect_mode = SRC_AUTHSELECT_IGNORE;
|
||||
else
|
||||
command_parse_error();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_bindacqaddress(char *line)
|
||||
{
|
||||
@@ -1188,8 +1316,10 @@ parse_bindcmdaddress(char *line)
|
||||
if (line[0] == '/') {
|
||||
parse_string(line, &bind_cmd_path);
|
||||
/* / disables the socket */
|
||||
if (!strcmp(bind_cmd_path, "/"))
|
||||
bind_cmd_path[0] = '\0';
|
||||
if (strcmp(bind_cmd_path, "/") == 0) {
|
||||
Free(bind_cmd_path);
|
||||
bind_cmd_path = NULL;
|
||||
}
|
||||
} else if (UTI_StringToIP(line, &ip)) {
|
||||
if (ip.family == IPADDR_INET4)
|
||||
bind_cmd_address4 = ip;
|
||||
@@ -1242,8 +1372,8 @@ parse_broadcast(char *line)
|
||||
}
|
||||
|
||||
destination = (NTP_Broadcast_Destination *)ARR_GetNewElement(broadcasts);
|
||||
destination->addr = ip;
|
||||
destination->port = port;
|
||||
destination->addr.ip_addr = ip;
|
||||
destination->addr.port = port;
|
||||
destination->interval = interval;
|
||||
}
|
||||
|
||||
@@ -1386,6 +1516,86 @@ parse_hwtimestamp(char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static const char *
|
||||
get_basename(const char *path)
|
||||
{
|
||||
const char *b = strrchr(path, '/');
|
||||
return b ? b + 1 : path;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
compare_basenames(const void *a, const void *b)
|
||||
{
|
||||
return strcmp(get_basename(*(const char * const *)a),
|
||||
get_basename(*(const char * const *)b));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
search_dirs(char *line, const char *suffix, void (*file_handler)(const char *path))
|
||||
{
|
||||
char *dirs[MAX_CONF_DIRS], buf[MAX_LINE_LENGTH], *path;
|
||||
size_t i, j, k, locations, n_dirs;
|
||||
glob_t gl;
|
||||
|
||||
n_dirs = UTI_SplitString(line, dirs, MAX_CONF_DIRS);
|
||||
if (n_dirs < 1 || n_dirs > MAX_CONF_DIRS)
|
||||
return 0;
|
||||
|
||||
/* Get the paths of all config files in the specified directories */
|
||||
for (i = 0; i < n_dirs; i++) {
|
||||
if (snprintf(buf, sizeof (buf), "%s/*%s", dirs[i], suffix) >= sizeof (buf))
|
||||
assert(0);
|
||||
if (glob(buf, GLOB_NOSORT | (i > 0 ? GLOB_APPEND : 0), NULL, &gl) != 0)
|
||||
;
|
||||
}
|
||||
|
||||
if (gl.gl_pathc > 0) {
|
||||
/* Sort the paths by filenames */
|
||||
qsort(gl.gl_pathv, gl.gl_pathc, sizeof (gl.gl_pathv[0]), compare_basenames);
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i += locations) {
|
||||
/* Count directories containing files with this name */
|
||||
for (j = i + 1, locations = 1; j < gl.gl_pathc; j++, locations++) {
|
||||
if (compare_basenames(&gl.gl_pathv[i], &gl.gl_pathv[j]) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read the first file of this name in the order of the directive */
|
||||
for (j = 0; j < n_dirs; j++) {
|
||||
for (k = 0; k < locations; k++) {
|
||||
path = gl.gl_pathv[i + k];
|
||||
if (strncmp(path, dirs[j], strlen(dirs[j])) == 0 &&
|
||||
strlen(dirs[j]) + 1 + strlen(get_basename(path)) == strlen(path)) {
|
||||
file_handler(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k < locations)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
globfree(&gl);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_confdir(char *line)
|
||||
{
|
||||
if (!search_dirs(line, ".conf", CNF_ReadFile))
|
||||
command_parse_error();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_include(char *line)
|
||||
{
|
||||
@@ -1415,13 +1625,144 @@ parse_include(char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
load_source_file(const char *filename)
|
||||
{
|
||||
char line[MAX_LINE_LENGTH + 1];
|
||||
FILE *f;
|
||||
|
||||
f = UTI_OpenFile(NULL, filename, NULL, 'r', 0);
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
while (fgets(line, sizeof (line), f)) {
|
||||
if (strlen(line) >= MAX_LINE_LENGTH)
|
||||
continue;
|
||||
|
||||
CPS_NormalizeLine(line);
|
||||
if (line[0] == '\0')
|
||||
continue;
|
||||
|
||||
parse_source(CPS_SplitWord(line), line, 0);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
compare_sources(const void *a, const void *b)
|
||||
{
|
||||
const NTP_Source *sa = a, *sb = b;
|
||||
int d;
|
||||
|
||||
if (!sa->params.name)
|
||||
return -1;
|
||||
if (!sb->params.name)
|
||||
return 1;
|
||||
if ((d = strcmp(sa->params.name, sb->params.name)) != 0)
|
||||
return d;
|
||||
if ((d = (int)(sa->type) - (int)(sb->type)) != 0)
|
||||
return d;
|
||||
if ((d = sa->pool - sb->pool) != 0)
|
||||
return d;
|
||||
if ((d = sa->params.port - sb->params.port) != 0)
|
||||
return d;
|
||||
return memcmp(&sa->params.params, &sb->params.params, sizeof (sa->params.params));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
reload_source_dirs(void)
|
||||
{
|
||||
NTP_Source *prev_sources, *new_sources, *source;
|
||||
unsigned int i, j, prev_size, new_size, unresolved;
|
||||
uint32_t *prev_ids, *new_ids;
|
||||
char buf[MAX_LINE_LENGTH];
|
||||
NSR_Status s;
|
||||
int d;
|
||||
|
||||
prev_size = ARR_GetSize(ntp_source_ids);
|
||||
if (prev_size > 0 && ARR_GetSize(ntp_sources) != prev_size)
|
||||
assert(0);
|
||||
|
||||
/* Save the current sources and their configuration IDs */
|
||||
prev_ids = MallocArray(uint32_t, prev_size);
|
||||
memcpy(prev_ids, ARR_GetElements(ntp_source_ids), prev_size * sizeof (prev_ids[0]));
|
||||
prev_sources = MallocArray(NTP_Source, prev_size);
|
||||
memcpy(prev_sources, ARR_GetElements(ntp_sources), prev_size * sizeof (prev_sources[0]));
|
||||
|
||||
/* Load the sources again */
|
||||
ARR_SetSize(ntp_sources, 0);
|
||||
for (i = 0; i < ARR_GetSize(ntp_source_dirs); i++) {
|
||||
if (snprintf(buf, sizeof (buf), "%s",
|
||||
*(char **)ARR_GetElement(ntp_source_dirs, i)) >= sizeof (buf))
|
||||
assert(0);
|
||||
search_dirs(buf, ".sources", load_source_file);
|
||||
}
|
||||
|
||||
/* Add new and remove existing sources according to the new configuration.
|
||||
Avoid removing and adding the same source again to keep its state. */
|
||||
|
||||
new_size = ARR_GetSize(ntp_sources);
|
||||
new_sources = ARR_GetElements(ntp_sources);
|
||||
ARR_SetSize(ntp_source_ids, new_size);
|
||||
new_ids = ARR_GetElements(ntp_source_ids);
|
||||
unresolved = 0;
|
||||
|
||||
qsort(new_sources, new_size, sizeof (new_sources[0]), compare_sources);
|
||||
|
||||
for (i = j = 0; i < prev_size || j < new_size; ) {
|
||||
if (i < prev_size && j < new_size)
|
||||
d = compare_sources(&prev_sources[i], &new_sources[j]);
|
||||
else
|
||||
d = i < prev_size ? -1 : 1;
|
||||
|
||||
if (d < 0) {
|
||||
/* Remove the missing source */
|
||||
if (prev_sources[i].params.name[0] != '\0')
|
||||
NSR_RemoveSourcesById(prev_ids[i]);
|
||||
i++;
|
||||
} else if (d > 0) {
|
||||
/* Add a newly configured source */
|
||||
source = &new_sources[j];
|
||||
s = NSR_AddSourceByName(source->params.name, source->params.port, source->pool,
|
||||
source->type, &source->params.params, &new_ids[j]);
|
||||
|
||||
if (s == NSR_UnresolvedName) {
|
||||
unresolved++;
|
||||
} else if (s != NSR_Success) {
|
||||
/* Mark the source as not present */
|
||||
source->params.name[0] = '\0';
|
||||
}
|
||||
j++;
|
||||
} else {
|
||||
/* Keep the existing source */
|
||||
new_ids[j] = prev_ids[i];
|
||||
i++, j++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < prev_size; i++)
|
||||
Free(prev_sources[i].params.name);
|
||||
Free(prev_sources);
|
||||
Free(prev_ids);
|
||||
|
||||
if (unresolved > 0)
|
||||
NSR_ResolveSources();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CNF_CreateDirs(uid_t uid, gid_t gid)
|
||||
{
|
||||
char *dir;
|
||||
|
||||
/* Create a directory for the Unix domain command socket */
|
||||
if (bind_cmd_path[0]) {
|
||||
if (bind_cmd_path) {
|
||||
dir = UTI_PathToDir(bind_cmd_path);
|
||||
UTI_CreateDirAndParents(dir, 0770, uid, gid);
|
||||
|
||||
@@ -1430,16 +1771,19 @@ CNF_CreateDirs(uid_t uid, gid_t gid)
|
||||
domain sockets are ignored on some systems (e.g. Solaris). */
|
||||
if (!UTI_CheckDirPermissions(dir, 0770, uid, gid)) {
|
||||
LOG(LOGS_WARN, "Disabled command socket %s", bind_cmd_path);
|
||||
bind_cmd_path[0] = '\0';
|
||||
Free(bind_cmd_path);
|
||||
bind_cmd_path = NULL;
|
||||
}
|
||||
|
||||
Free(dir);
|
||||
}
|
||||
|
||||
if (logdir[0])
|
||||
UTI_CreateDirAndParents(logdir, 0755, uid, gid);
|
||||
if (dumpdir[0])
|
||||
UTI_CreateDirAndParents(dumpdir, 0755, uid, gid);
|
||||
if (logdir)
|
||||
UTI_CreateDirAndParents(logdir, 0750, uid, gid);
|
||||
if (dumpdir)
|
||||
UTI_CreateDirAndParents(dumpdir, 0750, uid, gid);
|
||||
if (nts_dump_dir)
|
||||
UTI_CreateDirAndParents(nts_dump_dir, 0750, uid, gid);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1456,13 +1800,12 @@ CNF_AddInitSources(void)
|
||||
/* Get the default NTP params */
|
||||
CPS_ParseNTPSourceAdd(dummy_hostname, &cps_source);
|
||||
|
||||
/* Add the address as an offline iburst server */
|
||||
/* Add the address as a server specified with the iburst option */
|
||||
ntp_addr.ip_addr = *(IPAddr *)ARR_GetElement(init_sources, i);
|
||||
ntp_addr.port = cps_source.port;
|
||||
cps_source.params.iburst = 1;
|
||||
cps_source.params.connectivity = SRC_OFFLINE;
|
||||
|
||||
NSR_AddSource(&ntp_addr, NTP_SERVER, &cps_source.params);
|
||||
NSR_AddSource(&ntp_addr, NTP_SERVER, &cps_source.params, NULL);
|
||||
}
|
||||
|
||||
ARR_SetSize(init_sources, 0);
|
||||
@@ -1479,11 +1822,13 @@ CNF_AddSources(void)
|
||||
for (i = 0; i < ARR_GetSize(ntp_sources); i++) {
|
||||
source = (NTP_Source *)ARR_GetElement(ntp_sources, i);
|
||||
NSR_AddSourceByName(source->params.name, source->params.port,
|
||||
source->pool, source->type, &source->params.params);
|
||||
source->pool, source->type, &source->params.params, NULL);
|
||||
Free(source->params.name);
|
||||
}
|
||||
|
||||
ARR_SetSize(ntp_sources, 0);
|
||||
|
||||
reload_source_dirs();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1510,8 +1855,7 @@ CNF_AddBroadcasts(void)
|
||||
|
||||
for (i = 0; i < ARR_GetSize(broadcasts); i++) {
|
||||
destination = (NTP_Broadcast_Destination *)ARR_GetElement(broadcasts, i);
|
||||
NCR_AddBroadcastDestination(&destination->addr, destination->port,
|
||||
destination->interval);
|
||||
NCR_AddBroadcastDestination(&destination->addr, destination->interval);
|
||||
}
|
||||
|
||||
ARR_SetSize(broadcasts, 0);
|
||||
@@ -1519,6 +1863,14 @@ CNF_AddBroadcasts(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CNF_ReloadSources(void)
|
||||
{
|
||||
reload_source_dirs();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetNTPPort(void)
|
||||
{
|
||||
@@ -1680,6 +2032,14 @@ CNF_GetCorrectionTimeRatio(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
SRC_AuthSelectMode
|
||||
CNF_GetAuthSelectMode(void)
|
||||
{
|
||||
return authselect_mode;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
CNF_GetMaxSlewRate(void)
|
||||
{
|
||||
@@ -1897,6 +2257,30 @@ CNF_GetBindAcquisitionAddress(int family, IPAddr *addr)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetBindNtpInterface(void)
|
||||
{
|
||||
return bind_ntp_iface;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetBindAcquisitionInterface(void)
|
||||
{
|
||||
return bind_acq_iface;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetBindCommandInterface(void)
|
||||
{
|
||||
return bind_cmd_iface;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetBindCommandPath(void)
|
||||
{
|
||||
@@ -1918,6 +2302,14 @@ CNF_GetBindCommandAddress(int family, IPAddr *addr)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetNtpDscp(void)
|
||||
{
|
||||
return ntp_dscp;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetNtpSigndSocket(void)
|
||||
{
|
||||
@@ -1976,6 +2368,16 @@ int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int CNF_GetNtsRateLimit(int *interval, int *burst, int *leak)
|
||||
{
|
||||
*interval = nts_ratelimit_interval;
|
||||
*burst = nts_ratelimit_burst;
|
||||
*leak = nts_ratelimit_leak;
|
||||
return nts_ratelimit_enabled;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int CNF_GetCommandRateLimit(int *interval, int *burst, int *leak)
|
||||
{
|
||||
*interval = cmd_ratelimit_interval;
|
||||
|
||||
11
conf.h
11
conf.h
@@ -30,10 +30,13 @@
|
||||
|
||||
#include "addressing.h"
|
||||
#include "reference.h"
|
||||
#include "sources.h"
|
||||
|
||||
extern void CNF_Initialise(int restarted, int client_only);
|
||||
extern void CNF_Finalise(void);
|
||||
|
||||
extern void CNF_EnablePrint(void);
|
||||
|
||||
extern char *CNF_GetRtcDevice(void);
|
||||
|
||||
extern void CNF_ReadFile(const char *filename);
|
||||
@@ -46,6 +49,8 @@ extern void CNF_AddSources(void);
|
||||
extern void CNF_AddBroadcasts(void);
|
||||
extern void CNF_AddRefclocks(void);
|
||||
|
||||
extern void CNF_ReloadSources(void);
|
||||
|
||||
extern int CNF_GetAcquisitionPort(void);
|
||||
extern int CNF_GetNTPPort(void);
|
||||
extern char *CNF_GetDriftFile(void);
|
||||
@@ -74,7 +79,11 @@ extern void CNF_GetFallbackDrifts(int *min, int *max);
|
||||
extern void CNF_GetBindAddress(int family, IPAddr *addr);
|
||||
extern void CNF_GetBindAcquisitionAddress(int family, IPAddr *addr);
|
||||
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
|
||||
extern char *CNF_GetBindNtpInterface(void);
|
||||
extern char *CNF_GetBindAcquisitionInterface(void);
|
||||
extern char *CNF_GetBindCommandInterface(void);
|
||||
extern char *CNF_GetBindCommandPath(void);
|
||||
extern int CNF_GetNtpDscp(void);
|
||||
extern char *CNF_GetNtpSigndSocket(void);
|
||||
extern char *CNF_GetPidFile(void);
|
||||
extern REF_LeapMode CNF_GetLeapSecMode(void);
|
||||
@@ -87,6 +96,7 @@ extern double CNF_GetMaxDrift(void);
|
||||
extern double CNF_GetCorrectionTimeRatio(void);
|
||||
extern double CNF_GetMaxSlewRate(void);
|
||||
|
||||
extern SRC_AuthSelectMode CNF_GetAuthSelectMode(void);
|
||||
extern double CNF_GetMaxDistance(void);
|
||||
extern double CNF_GetMaxJitter(void);
|
||||
extern double CNF_GetReselectDistance(void);
|
||||
@@ -101,6 +111,7 @@ extern int CNF_GetSchedPriority(void);
|
||||
extern int CNF_GetLockMemory(void);
|
||||
|
||||
extern int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak);
|
||||
extern int CNF_GetNtsRateLimit(int *interval, int *burst, int *leak);
|
||||
extern int CNF_GetCommandRateLimit(int *interval, int *burst, int *leak);
|
||||
extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only);
|
||||
extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
|
||||
|
||||
43
configure
vendored
43
configure
vendored
@@ -657,6 +657,7 @@ if [ $feat_ipv6 = "1" ] && \
|
||||
struct sockaddr_in6 n;
|
||||
char p[100];
|
||||
n.sin6_addr = in6addr_any;
|
||||
n.sin6_scope_id = 0;
|
||||
return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));'
|
||||
then
|
||||
add_def FEAT_IPV6
|
||||
@@ -939,7 +940,7 @@ fi
|
||||
|
||||
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nss = "1" ]; then
|
||||
test_cflags="`pkg_config --cflags nss`"
|
||||
test_link="`pkg_config --libs-only-L nss` -lfreebl3"
|
||||
test_link="`pkg_config --libs-only-L nss` -lfreebl3 -lnssutil3"
|
||||
if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
|
||||
"$test_cflags" "$test_link" \
|
||||
'NSSLOWHASH_Begin(NSSLOWHASH_NewContext(NSSLOW_Init(), HASH_AlgSHA512));'
|
||||
@@ -966,31 +967,45 @@ 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" ] && \
|
||||
echo "$HASH_LINK" | grep 'nettle' > /dev/null; then
|
||||
if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then
|
||||
test_cflags="`pkg_config --cflags gnutls`"
|
||||
test_link="`pkg_config --libs gnutls`"
|
||||
if test_code 'gnutls' 'gnutls/gnutls.h' \
|
||||
"$test_cflags" "$test_link" '
|
||||
return gnutls_init(NULL, 0) +
|
||||
gnutls_priority_init2(NULL, "", NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND) +
|
||||
gnutls_prf_rfc5705(NULL, 0, "", 0, "", 16, NULL);' &&
|
||||
test_code 'AES128 in nettle' 'nettle/aes.h' '' "$LIBS" \
|
||||
'aes128_set_encrypt_key(NULL, NULL);'
|
||||
gnutls_prf_rfc5705(NULL, 0, "", 0, "", 16, NULL);'
|
||||
then
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS nts_ke_client.o nts_ke_server.o nts_ke_session.o"
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS nts_ntp_auth.o nts_ntp_client.o nts_ntp_server.o"
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_nettle.o"
|
||||
LIBS="$LIBS $test_link"
|
||||
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
|
||||
add_def FEAT_NTS
|
||||
|
||||
add_def HAVE_SIV
|
||||
if test_code 'SIV in nettle' \
|
||||
'nettle/siv-cmac.h' "" "$LIBS" \
|
||||
'siv_cmac_aes128_set_key(NULL, NULL);'
|
||||
then
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_nettle.o"
|
||||
add_def HAVE_SIV
|
||||
add_def HAVE_NETTLE_SIV_CMAC
|
||||
else
|
||||
if test_code 'SIV in gnutls' 'gnutls/gnutls.h' \
|
||||
"$test_cflags" "$test_link" '
|
||||
return gnutls_aead_cipher_init(NULL, GNUTLS_CIPHER_AES_128_SIV, NULL);'
|
||||
then
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_gnutls.o"
|
||||
add_def HAVE_SIV
|
||||
else
|
||||
if test_code 'AES128 in nettle' 'nettle/aes.h' '' "$LIBS" \
|
||||
'aes128_set_encrypt_key(NULL, NULL);'
|
||||
then
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_nettle.o"
|
||||
add_def HAVE_SIV
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if grep '#define HAVE_SIV' config.h > /dev/null; then
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS nts_ke_client.o nts_ke_server.o nts_ke_session.o"
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS nts_ntp_auth.o nts_ntp_client.o nts_ntp_server.o"
|
||||
LIBS="$LIBS $test_link"
|
||||
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
|
||||
add_def FEAT_NTS
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -82,13 +82,13 @@ interval should stay at or below 9 (512 seconds). The default is 10 (1024
|
||||
seconds), the minimum is -6 (1/64th of a second), and the maximum is 24 (6
|
||||
months).
|
||||
*iburst*:::
|
||||
With this option, the interval between the first four requests sent to the
|
||||
server will be 2 seconds or less instead of the interval specified by the
|
||||
*minpoll* option, which allows *chronyd* to make the first update of the clock
|
||||
shortly after start.
|
||||
With this option, *chronyd* will start with a burst of 4-8 requests in order to
|
||||
make the first update of the clock sooner. It will also repeat the burst every
|
||||
time the source is switched from the offline state to online with the
|
||||
<<chronyc.adoc#online,*online*>> command in *chronyc*.
|
||||
*burst*:::
|
||||
With this option, *chronyd* will shorten the interval between up to four
|
||||
requests to 2 seconds or less when it cannot get a good measurement from the
|
||||
With this option, *chronyd* will send a burst of up to 4 requests when it
|
||||
cannot get a good measurement from the
|
||||
server. The number of requests in the burst is limited by the current polling
|
||||
interval to keep the average interval at or above the minimum interval, i.e.
|
||||
the current interval needs to be at least two times longer than the minimum
|
||||
@@ -200,10 +200,11 @@ authenticated source to be safely combined with unauthenticated sources in
|
||||
order to improve the accuracy of the clock. They can be selected and used for
|
||||
synchronisation only if they agree with the trusted and required source.
|
||||
*xleave*:::
|
||||
This option enables an interleaved mode which enables the server to
|
||||
send transmit timestamps captured after the actual transmission (e.g. when the
|
||||
server is running *chronyd* with software (kernel) or hardware
|
||||
timestamping). This can significantly improve the accuracy of the measurements.
|
||||
This option enables the interleaved mode of NTP. It enables the server to
|
||||
respond with more accurate transmit timestamps (e.g. kernel or hardware
|
||||
timestamps), which cannot be contained in the transmitted packet itself and
|
||||
need to refer to a previous packet instead. This can significantly improve the
|
||||
accuracy and stability of the measurements.
|
||||
+
|
||||
The interleaved mode is compatible with servers that support only the basic
|
||||
mode. Note that even
|
||||
@@ -228,7 +229,7 @@ be specified. For normal servers this option should not be required (the
|
||||
default is 123, the standard NTP port).
|
||||
*ntsport* _port_:::
|
||||
This option specifies the TCP port on which the server is listening for NTS-KE
|
||||
connections when the *nts* option is enabled. The default is 11443.
|
||||
connections when the *nts* option is enabled. The default is 4460.
|
||||
*presend* _poll_:::
|
||||
If the timing measurements being made by *chronyd* are the only network data
|
||||
passing between two computers, you might find that some measurements are badly
|
||||
@@ -284,7 +285,7 @@ This option sets the desired number of sources to be used from the pool.
|
||||
sources responding to requests. The default value is 4 and the maximum value is
|
||||
16.
|
||||
+
|
||||
::
|
||||
{blank}::
|
||||
When an NTP source is unreachable,
|
||||
marked as a falseticker, or has a distance larger than the limit set by the
|
||||
<<maxdistance,*maxdistance*>> directive, *chronyd* will try to replace the
|
||||
@@ -412,7 +413,7 @@ By default, the PPS refclock uses assert events (rising edge) for
|
||||
synchronisation. With this option, it will use clear events (falling edge)
|
||||
instead.
|
||||
+
|
||||
:::
|
||||
{blank}:::
|
||||
Examples:
|
||||
+
|
||||
----
|
||||
@@ -431,7 +432,7 @@ supports the following option:
|
||||
This option specifies the permissions of the shared memory segment created by
|
||||
*chronyd*. They are specified as a numeric mode. The default value is 0600
|
||||
(read-write access for owner only).
|
||||
:::
|
||||
{blank}:::
|
||||
+
|
||||
Examples:
|
||||
+
|
||||
@@ -485,7 +486,7 @@ value is 0.
|
||||
This option enables timestamping of clear events (falling edge) instead of
|
||||
assert events (rising edge) in the PPS mode. This may not work with some
|
||||
clocks.
|
||||
:::
|
||||
{blank}:::
|
||||
+
|
||||
Examples:
|
||||
+
|
||||
@@ -495,7 +496,7 @@ refclock PHC /dev/ptp1:nocrossts poll 3 pps
|
||||
refclock PHC /dev/ptp2:extpps:pin=1 width 0.2 poll 2
|
||||
----
|
||||
+
|
||||
::
|
||||
{blank}::
|
||||
The *refclock* directive supports the following options:
|
||||
+
|
||||
*poll* _poll_:::
|
||||
@@ -630,7 +631,7 @@ This would change the source port used for client requests to UDP port 1123.
|
||||
You could then persuade the firewall administrator to open that port.
|
||||
|
||||
[[bindacqaddress]]*bindacqaddress* _address_::
|
||||
The *bindacqaddress* directive sets the network interface to which
|
||||
The *bindacqaddress* directive specifies a local IP address to which
|
||||
*chronyd* will bind its NTP client sockets. The syntax is similar to the
|
||||
<<bindaddress,*bindaddress*>> and <<bindcmdaddress,*bindcmdaddress*>>
|
||||
directives.
|
||||
@@ -638,6 +639,32 @@ directives.
|
||||
For each of the IPv4 and IPv6 protocols, only one *bindacqaddress* directive
|
||||
can be specified.
|
||||
|
||||
[[bindacqdevice]]*bindacqdevice* _interface_::
|
||||
The *bindacqdevice* directive binds the client sockets to a network device
|
||||
specified by the interface name. This can be useful when the local address is
|
||||
dynamic, or to enable an NTP source specified with a link-local IPv6 address.
|
||||
This directive can specify only one interface and it is supported on Linux
|
||||
only.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
bindacqdevice eth0
|
||||
----
|
||||
|
||||
[[dscp]]*dscp* _point_::
|
||||
The *dscp* directive sets the Differentiated Services Code Point (DSCP) in
|
||||
transmitted NTP packets to the specified value. It can improve stability of NTP
|
||||
measurements in local networks where switches or routers are configured to
|
||||
prioritise forwarding of packets with specific DSCP values. The default value
|
||||
is 0 and the maximum value is 63.
|
||||
+
|
||||
An example of the directive (setting the Expedited Forwarding class) is:
|
||||
+
|
||||
----
|
||||
dscp 46
|
||||
----
|
||||
|
||||
[[dumpdir]]*dumpdir* _directory_::
|
||||
To compute the rate of gain or loss of time, *chronyd* has to store a
|
||||
measurement history for each of the time sources it uses.
|
||||
@@ -655,6 +682,8 @@ behaviour whilst it is not running). The *dumpdir* directive defines the
|
||||
directory where the measurement histories are saved when *chronyd* exits,
|
||||
or the <<chronyc.adoc#dump,*dump*>> command in *chronyc* is issued.
|
||||
+
|
||||
If the directory does not exist, it will be created automatically.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
@@ -696,6 +725,8 @@ received from the server in order to avoid making an NTS-KE request when
|
||||
source in files named by the IP address of the NTS-KE server (e.g.
|
||||
_1.2.3.4.nts_). By default, the client does not save the cookies.
|
||||
+
|
||||
If the directory does not exist, it will be created automatically.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
@@ -726,7 +757,7 @@ authentication mechanism to be used on computers which start with wrong time
|
||||
has important security implications, e.g. if an NTP server was ever
|
||||
compromised, its certificate could be used in an attack after the expiration
|
||||
time. The default value is 0, which means the time checks are always enabled.
|
||||
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
@@ -739,6 +770,78 @@ with correct time.
|
||||
|
||||
=== Source selection
|
||||
|
||||
[[authselectmode]]*authselectmode* _mode_::
|
||||
NTP sources can be specified with the *key* or *nts* option to enable
|
||||
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
|
||||
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
|
||||
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
|
||||
authenticated sources and might have a positive impact on the accuracy of the
|
||||
clock. Note that in this case the impact of the attack is higher. The attackers
|
||||
cannot cause an arbitrarily large step or slew, but they have more control over
|
||||
the frequency of the clock and can cause *chronyd* to report false information,
|
||||
e.g. a significantly smaller root delay and dispersion.
|
||||
+
|
||||
This directive determines the default selection options for authenticated and
|
||||
unauthenticated sources in order to simplify the configuration with the
|
||||
configuration file and *chronyc* commands. It sets a policy for authentication.
|
||||
+
|
||||
Sources specified with the *noselect* option are ignored (not counted as either
|
||||
authenticated or unauthenticated), and they always have only the selection
|
||||
options specified in the configuration.
|
||||
+
|
||||
There are four modes:
|
||||
+
|
||||
*require*:::
|
||||
Authentication is strictly required for NTP sources in this mode. If any
|
||||
unauthenticated NTP sources are specified, they will automatically get the
|
||||
*noselect* option to prevent them from being selected for synchronisation.
|
||||
*prefer*:::
|
||||
In this mode, authentication is optional and preferred. If it is enabled for at
|
||||
least one NTP source, all unauthenticated NTP sources will get the *noselect*
|
||||
option.
|
||||
*mix*:::
|
||||
In this mode, authentication is optional and synchronisation to a mix of
|
||||
authenticated and unauthenticated NTP sources is allowed. If both authenticated
|
||||
and unauthenticated NTP sources are specified, all authenticated NTP sources
|
||||
and reference clocks will get the *require* and *trust* options to prevent
|
||||
synchronisation to unauthenticated NTP sources if they do not agree with a
|
||||
majority of the authenticated sources and reference clocks. This is the default
|
||||
mode.
|
||||
*ignore*:::
|
||||
In this mode, authentication is ignored in the source selection. All sources
|
||||
will have only the selection options that were specified in the configuration
|
||||
file, or *chronyc* command. This was the behaviour of *chronyd* in versions
|
||||
before 4.0.
|
||||
{blank}::
|
||||
+
|
||||
As an example, the following configuration using the default *mix* mode:
|
||||
+
|
||||
----
|
||||
server foo.example.net nts
|
||||
server bar.example.net nts
|
||||
server baz.example.net
|
||||
refclock SHM 0
|
||||
----
|
||||
+
|
||||
is equivalent to the following configuration using the *ignore* mode:
|
||||
+
|
||||
----
|
||||
authselectmode ignore
|
||||
server foo.example.net nts require trust
|
||||
server bar.example.net nts require trust
|
||||
server baz.example.net
|
||||
refclock SHM 0 require trust
|
||||
----
|
||||
|
||||
[[combinelimit]]*combinelimit* _limit_::
|
||||
When *chronyd* has multiple sources available for synchronisation, it has to
|
||||
select one source as the synchronisation source. The measured offsets and
|
||||
@@ -913,7 +1016,7 @@ clock will be off for a longer time. On Linux with the default
|
||||
No correction is applied to the clock for the leap second. The clock will be
|
||||
corrected later in normal operation when new measurements are made and the
|
||||
estimated offset includes the one second error.
|
||||
::
|
||||
{blank}::
|
||||
+
|
||||
When serving time to NTP clients that cannot be configured to correct their
|
||||
clocks for a leap second by slewing, or to clients that would correct at
|
||||
@@ -1264,6 +1367,17 @@ Currently, for each of the IPv4 and IPv6 protocols, only one *bindaddress*
|
||||
directive can be specified. Therefore, it is not useful on computers which
|
||||
should serve NTP on multiple network interfaces.
|
||||
|
||||
[[binddevice]]*binddevice* _interface_::
|
||||
The *binddevice* directive binds the NTP server sockets to a network device
|
||||
specified by the interface name. This directive can specify only one interface
|
||||
and it is supported on Linux only.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
binddevice eth0
|
||||
----
|
||||
|
||||
[[broadcast]]*broadcast* _interval_ _address_ [_port_]::
|
||||
The *broadcast* directive is used to declare a broadcast address to which
|
||||
chronyd should send packets in the NTP broadcast mode (i.e. make *chronyd* act
|
||||
@@ -1373,7 +1487,7 @@ synchronised to it. When that server fails, another will take over.
|
||||
+
|
||||
The *orphan* mode is compatible with the *ntpd*'s orphan mode (enabled by the
|
||||
*tos orphan* command).
|
||||
::
|
||||
{blank}::
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
@@ -1400,7 +1514,7 @@ ntpsigndsocket /var/lib/samba/ntp_signd
|
||||
|
||||
[[ntsport]]*ntsport* _port_::
|
||||
This directive specifies the TCP port on which *chronyd* will provide the NTS
|
||||
Key Establishment (NTS-KE) service. The default port is 11443.
|
||||
Key Establishment (NTS-KE) service. The default port is 4460.
|
||||
+
|
||||
The port will be open only when a certificate and key is specified by the
|
||||
*ntsservercert* and *ntsserverkey* directives.
|
||||
@@ -1516,7 +1630,7 @@ 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
|
||||
maximum value is 4.
|
||||
::
|
||||
{blank}::
|
||||
+
|
||||
An example use of the directive is:
|
||||
+
|
||||
@@ -1528,6 +1642,17 @@ This would reduce the response rate for IP addresses sending packets on average
|
||||
more than once per 2 seconds, or sending packets in bursts of more than 16
|
||||
packets, by up to 75% (with default *leak* of 2).
|
||||
|
||||
[[ntsratelimit]]*ntsratelimit* [_option_]...::
|
||||
This directive enables rate limiting of NTS-KE requests. It is similar to the
|
||||
<<ratelimit,*ratelimit*>> directive, except the default interval is 6
|
||||
(1 connection per 64 seconds).
|
||||
+
|
||||
An example of the use of the directive is:
|
||||
+
|
||||
----
|
||||
ntsratelimit interval 3 burst 1
|
||||
----
|
||||
|
||||
[[smoothtime]]*smoothtime* _max-freq_ _max-wander_ [*leaponly*]::
|
||||
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
|
||||
@@ -1581,8 +1706,8 @@ smoothtime 50000 0.01
|
||||
=== Command and monitoring access
|
||||
|
||||
[[bindcmdaddress]]*bindcmdaddress* _address_::
|
||||
The *bindcmdaddress* directive allows you to specify an IP address of an
|
||||
interface on which *chronyd* will listen for monitoring command packets (issued
|
||||
The *bindcmdaddress* directive specifies a local IP address to which *chronyd*
|
||||
will bind the UDP socket listening for monitoring command packets (issued
|
||||
by *chronyc*). On systems other than Linux, the address of the interface needs
|
||||
to be already configured when *chronyd* is started.
|
||||
+
|
||||
@@ -1593,9 +1718,10 @@ directory will be created on start if it does not exist. The compiled-in default
|
||||
path of the socket is _@CHRONYRUNDIR@/chronyd.sock_. The socket can be
|
||||
disabled by setting the path to _/_.
|
||||
+
|
||||
By default, *chronyd* binds to the loopback interface (with addresses
|
||||
_127.0.0.1_ and _::1_). This blocks all access except from localhost. To listen
|
||||
for command packets on all interfaces, you can add the lines:
|
||||
By default, *chronyd* binds the UDP sockets to the addresses _127.0.0.1_ and
|
||||
_::1_ (i.e. the loopback interface). This blocks all access except from
|
||||
localhost. To listen for command packets on all interfaces, you can add the
|
||||
lines:
|
||||
+
|
||||
----
|
||||
bindcmdaddress 0.0.0.0
|
||||
@@ -1613,6 +1739,17 @@ An example that sets the path of the Unix domain command socket is:
|
||||
bindcmdaddress /var/run/chrony/chronyd.sock
|
||||
----
|
||||
|
||||
[[bindcmddevice]]*bindcmddevice* _interface_::
|
||||
The *bindcmddevice* directive binds the UDP command sockets to a network device
|
||||
specified by the interface name. This directive can specify only one interface
|
||||
and it is supported on Linux only.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
bindcmddevice eth0
|
||||
----
|
||||
|
||||
[[cmdallow]]*cmdallow* [*all*] [_subnet_]::
|
||||
This is similar to the <<allow,*allow*>> directive, except that it allows
|
||||
monitoring access (rather than NTP client access) to a particular subnet or
|
||||
@@ -1991,7 +2128,7 @@ from the example line above):
|
||||
. Applied compensation in ppm, positive means the system clock is running
|
||||
faster than it would be without the compensation. [3.6600e-01]
|
||||
+
|
||||
::
|
||||
{blank}::
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
@@ -2024,8 +2161,9 @@ which would cause a syslog message to be generated if a system clock error of ov
|
||||
0.1 seconds starts to be compensated.
|
||||
|
||||
[[logdir]]*logdir* _directory_::
|
||||
This directive allows the directory where log files are written to be
|
||||
specified.
|
||||
This directive specifies the directory for writing log files enabled by the
|
||||
*log* directive. If the directory does not exist, it will be created
|
||||
automatically.
|
||||
+
|
||||
An example of the use of this directive is:
|
||||
+
|
||||
@@ -2053,6 +2191,50 @@ sendmail binary.
|
||||
|
||||
=== Miscellaneous
|
||||
|
||||
[[confdir]]*confdir* _directory_...::
|
||||
The *confdir* directive includes configuration files with the _.conf_ suffix
|
||||
from a directory. The files are included in the lexicographical order of the
|
||||
file names.
|
||||
+
|
||||
Multiple directories (up to 10) can be specified with a single *confdir*
|
||||
directive. In this case, if multiple directories contain a file with the same
|
||||
name, only the first file in the order of the specified directories will be
|
||||
included. This enables a fragmented configuration where existing fragments can
|
||||
be replaced by adding files to a different directory.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
confdir @SYSCONFDIR@/chrony.d
|
||||
----
|
||||
|
||||
[[sourcedir]]*sourcedir* _directory_...::
|
||||
The *sourcedir* directive is identical to the *confdir* directive, except the
|
||||
configuration files have the _.sources_ suffix, they can only specify NTP
|
||||
sources (i.e. use the *server*, *pool*, and *peer* directive), and can be
|
||||
reloaded by the <<chronyc.adoc#reload,*reload sources*>> command in
|
||||
*chronyc*. It is particularly useful with dynamic sources like NTP servers
|
||||
received from a DHCP server, which can be written to a file specific to the
|
||||
network interface by a networking script.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
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
|
||||
required to exist.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
include @SYSCONFDIR@/chrony.d/*.conf
|
||||
----
|
||||
|
||||
[[hwtimestamp]]*hwtimestamp* _interface_ [_option_]...::
|
||||
This directive enables hardware timestamping of NTP packets sent to and
|
||||
received from the specified network interface. The network interface controller
|
||||
@@ -2123,14 +2305,14 @@ _ntp_::::
|
||||
Enables timestamping of received NTP packets.
|
||||
_none_::::
|
||||
Disables timestamping of received packets.
|
||||
:::
|
||||
{blank}:::
|
||||
The most specific filter for timestamping NTP packets which is supported by the
|
||||
NIC is selected by default. Some NICs can timestamp only PTP packets, which
|
||||
limits the selection to the _none_ filter. Forcing timestamping of all packets
|
||||
with the _all_ filter when the NIC supports both _all_ and _ntp_ filters can be
|
||||
useful when packets are received from or on a non-standard UDP port (e.g.
|
||||
specified by the *port* directive).
|
||||
::
|
||||
{blank}::
|
||||
+
|
||||
Examples of the directive are:
|
||||
+
|
||||
@@ -2140,17 +2322,6 @@ hwtimestamp eth1 txcomp 300e-9 rxcomp 645e-9
|
||||
hwtimestamp *
|
||||
----
|
||||
|
||||
[[include]]*include* _pattern_::
|
||||
The *include* directive includes a configuration file or multiple configuration
|
||||
files if a wildcard pattern is specified. This can be useful when maintaining
|
||||
configuration on multiple hosts to keep the differences in separate files.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
include @SYSCONFDIR@/chrony.d/*.conf
|
||||
----
|
||||
|
||||
[[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
|
||||
|
||||
220
doc/chronyc.adoc
220
doc/chronyc.adoc
@@ -414,6 +414,92 @@ This is the estimated offset of the source.
|
||||
*Std Dev*:::
|
||||
This is the estimated sample standard deviation.
|
||||
|
||||
[[selectdata]]*selectdata* [*-a*] [*-v*]::
|
||||
The *selectdata* command displays information specific to the selection of time
|
||||
sources. If the *-a* option is specified, all sources are displayed, including
|
||||
those that do not have a known address yet. With the *-v* option, extra caption
|
||||
lines are shown as a reminder of the meanings of the columns.
|
||||
+
|
||||
An example of the output is shown below.
|
||||
+
|
||||
----
|
||||
S Name/IP Address Auth COpts EOpts Last Score Interval
|
||||
====================================================================
|
||||
D foo.example.net Y ----- --TR- 4 1.0 -61ms +62ms
|
||||
* bar.example.net N ----- ----- 0 1.0 -6846us +7305us
|
||||
+ baz.example.net N ----- ----- 10 1.0 -7381us +7355us
|
||||
----
|
||||
+
|
||||
The columns are as follows:
|
||||
+
|
||||
*S*:::
|
||||
This column indicates the state of the source after the last source selection.
|
||||
It is similar to the state reported by the *sources* command, but more
|
||||
states are reported.
|
||||
{blank}:::
|
||||
The following states indicate the source is not considered selectable for
|
||||
synchronisation:
|
||||
* _N_ - has the *noselect* option.
|
||||
* _M_ - does not have enough measurements.
|
||||
* _d_ - has a root distance larger than the maximum distance (configured by the
|
||||
<<chrony.conf.adoc#maxdistance,*maxdistance*>> directive).
|
||||
* _~_ - has a jitter larger than the maximum jitter (configured by the
|
||||
<<chrony.conf.adoc#maxjitter,*maxjitter*>> directive).
|
||||
* _w_ - waits for other sources to get out of the _M_ state.
|
||||
* _S_ - has older measurements than other sources.
|
||||
* _O_ - has a stratum equal or larger than the orphan stratum (configured by
|
||||
the <<chrony.conf.adoc#local,*local*>> directive).
|
||||
* _T_ - does not fully agree with sources that have the *trust* option.
|
||||
* _x_ - does not agree with other sources (falseticker).
|
||||
{blank}:::
|
||||
The following states indicate the source is considered selectable, but it is
|
||||
not currently used for synchronisation:
|
||||
* _W_ - waits for other sources to be selectable (required by the
|
||||
<<chrony.conf.adoc#minsources,*minsources*>> directive, or
|
||||
the *require* option of another source).
|
||||
* _P_ - another selectable source is preferred due to the *prefer* option.
|
||||
* _U_ - waits for a new measurement (after selecting a different best source).
|
||||
* _D_ - has, or recently had, a root distance which is too large to be combined
|
||||
with other sources (configured by the
|
||||
<<chrony.conf.adoc#combinelimit,*combinelimit*>> directive).
|
||||
{blank}:::
|
||||
The following states indicate the source is used for synchronisation of the
|
||||
local clock:
|
||||
* _+_ - combined with the best source.
|
||||
* _*_ - selected as the best source to update the reference data (e.g. root
|
||||
delay, root dispersion).
|
||||
*Name/IP address*:::
|
||||
This column shows the name or IP address of the source if it is an NTP server,
|
||||
or the reference ID if it is a reference clock.
|
||||
*Auth*:::
|
||||
This column indicites whether an authentication mechanism is enabled for the
|
||||
source. _Y_ means yes and _N_ means no.
|
||||
*COpts*:::
|
||||
This column displays the configured selection options of the source.
|
||||
* _N_ indicates the *noselect* option.
|
||||
* _P_ indicates the *prefer* option.
|
||||
* _T_ indicates the *trust* option.
|
||||
* _R_ indicates the *require* option.
|
||||
*EOpts*:::
|
||||
This column displays the current effective selection options of the source,
|
||||
which can be different from the configured options due to the authentication
|
||||
selection mode (configured by the
|
||||
<<chrony.conf.adoc#authselmode,*authselmode*>> directive). The symbols are the
|
||||
same as in the *COpts* column.
|
||||
*Last*:::
|
||||
This column displays how long ago was the last measurement of the source made
|
||||
when the selection was performed.
|
||||
*Score*:::
|
||||
This column displays the current score against the source in the _*_ state. The
|
||||
scoring system avoids frequent reselection when multiple sources have a similar
|
||||
root distance. A value larger than 1 indicates this source was better than the
|
||||
_*_ source in recent selections. If the score reaches 10, the best source will
|
||||
be reselected and the scores will be reset to 1.
|
||||
*Interval*:::
|
||||
This column displays the lower and upper endpoint of the interval which was
|
||||
expected to contain the true offset of the local clock considering the root
|
||||
distance at the time of the selection.
|
||||
|
||||
[[reselect]]*reselect*::
|
||||
To avoid excessive switching between sources, *chronyd* can stay synchronised
|
||||
to a source even when it is not currently the best one among the available
|
||||
@@ -454,6 +540,77 @@ the offline state.
|
||||
the name of the server or peer was not resolved to an address yet; this source is
|
||||
not visible in the *sources* and *sourcestats* reports.
|
||||
|
||||
[[authdata]]*authdata* [*-a*]::
|
||||
The *authdata* command displays information specific to authentication of NTP
|
||||
sources. If the *-a* option is specified, all sources are displayed, including
|
||||
those that do not have a known address yet. An example of the output is
|
||||
shown below.
|
||||
+
|
||||
----
|
||||
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
|
||||
=========================================================================
|
||||
foo.example.net NTS 1 15 256 135m 0 0 8 100
|
||||
bar.example.net SK 30 13 128 - 0 0 0 0
|
||||
baz.example.net - 0 0 0 - 0 0 0 0
|
||||
----
|
||||
+
|
||||
The columns are as follows:
|
||||
+
|
||||
*Name/IP address*:::
|
||||
This column shows the name or the IP address of the source.
|
||||
*Mode*:::
|
||||
This column shows which mechanism authenticates NTP packets received from the
|
||||
source. _NTS_ means Network Time Security, _SK_ means a symmetric key, and _-_
|
||||
means authentication is disabled.
|
||||
*KeyID*:::
|
||||
This column shows an identifier of the key used for authentication. With a
|
||||
symmetric key, it is the ID from the <<chrony.conf.adoc#keyfile,key file>>.
|
||||
With NTS, it is a number starting at zero and incremented by one with each
|
||||
successful key establishment using the NTS-KE protocol, i.e. it shows how many
|
||||
times the key establishment was performed with this source.
|
||||
*Type*:::
|
||||
This columns shows an identifier of the algorithm used for authentication.
|
||||
With a symmetric key, it is the hash function or cipher specified in the key
|
||||
file. With NTS, it is an authenticated encryption with associated data (AEAD)
|
||||
algorithm, which is negotiated in the NTS-KE protocol. The following values can
|
||||
be reported:
|
||||
* 1: MD5
|
||||
* 2: SHA1
|
||||
* 3: SHA256
|
||||
* 4: SHA384
|
||||
* 5: SHA512
|
||||
* 6: SHA3-224
|
||||
* 7: SHA3-256
|
||||
* 8: SHA3-384
|
||||
* 9: SHA3-512
|
||||
* 10: TIGER
|
||||
* 11: WHIRLPOOL
|
||||
* 13: AES128
|
||||
* 14: AES256
|
||||
* 15: AEAD-AES-SIV-CMAC-256
|
||||
*KLen*:::
|
||||
This column shows the length of the key in bits.
|
||||
*Last*:::
|
||||
This column shows how long ago the last successful key establishment was
|
||||
performed. It is in seconds, or letters _m_, _h_, _d_ or _y_ indicate minutes,
|
||||
hours, days, or years.
|
||||
*Atmp*:::
|
||||
This column shows the number of attempts to perform the key establishment since
|
||||
the last successful key establishment. A number larger than 1 indicates a
|
||||
problem with the network or server.
|
||||
*NAK*:::
|
||||
This column shows whether an NTS NAK was received since the last request.
|
||||
A NAK indicates that authentication failed on the server side due to
|
||||
*chronyd* using a cookie which is no longer valid and that it needs to perform
|
||||
the key establishment again in order to get new cookies.
|
||||
*Cook*:::
|
||||
This column shows the number of NTS cookies that *chronyd* currently has. If
|
||||
the key establishment was successful, a number smaller than 8 indicates a
|
||||
problem with the network or server.
|
||||
*CLen*:::
|
||||
This column shows the length in bytes of the NTS cookie which will be used in
|
||||
the next request.
|
||||
|
||||
[[ntpdata]]*ntpdata* [_address_]::
|
||||
The *ntpdata* command displays the last valid measurement and other
|
||||
NTP-specific information about the specified NTP source, or all NTP sources
|
||||
@@ -626,7 +783,7 @@ alternative to the form with mask.
|
||||
_address_:::
|
||||
This is an IP address or a hostname. The burst command is applied only to
|
||||
that source.
|
||||
::
|
||||
{blank}::
|
||||
+
|
||||
If no _mask_ or _masked-address_ arguments are provided, every source will be
|
||||
matched.
|
||||
@@ -771,6 +928,11 @@ Sources that stop responding will be replaced with newly resolved addresses
|
||||
automatically after 8 polling intervals, but this command can still be useful
|
||||
to replace them immediately and not wait until they are marked as unreachable.
|
||||
|
||||
[[reload]]*reload* *sources*::
|
||||
The *reload sources* command causes *chronyd* to re-read all _*.sources_ files
|
||||
from the directories specified by the
|
||||
<<chrony.conf.adoc#sourcedir,*sourcedir*>> directive.
|
||||
|
||||
[[sourcename]]*sourcename* _address_::
|
||||
The *sourcename* command prints the original hostname or address that was
|
||||
specified for an NTP source in the configuration file, or the *add* command.
|
||||
@@ -816,7 +978,7 @@ The columns are as as follows:
|
||||
. The regression residual at this point, in seconds. This allows '`outliers`'
|
||||
to be easily spotted, so that they can be deleted using the *manual delete*
|
||||
command.
|
||||
::
|
||||
{blank}::
|
||||
+
|
||||
The *delete* form of the command deletes a single sample. The parameter is the
|
||||
index of the sample, as shown in the first column of the output from *manual
|
||||
@@ -887,10 +1049,17 @@ This command can be used to examine the effect of a series of *allow*, *allow
|
||||
all*, *deny*, and *deny all* commands specified either via *chronyc*, or in
|
||||
*chronyd*'s configuration file.
|
||||
|
||||
[[clients]]*clients*::
|
||||
[[clients]]*clients* [*-p* _packets_] [*-k*] [*-r*]::
|
||||
This command shows a list of clients that have accessed the server, through
|
||||
either the NTP or command ports. It does not include accesses over
|
||||
the Unix domain command socket. There are no arguments.
|
||||
the NTP, command, or NTS-KE port. It does not include accesses over the Unix
|
||||
domain command socket.
|
||||
+
|
||||
The *-p* option specifies the minimum number of received NTP or command
|
||||
packets, or accepted NTS-KE connections, needed to include a client in the
|
||||
list. The default value is 0, i.e. all clients are reported. With the *-k*
|
||||
option the last four columns will show the NTS-KE accesses instead of command
|
||||
accesses. If the *-r* option is specified, *chronyd* will reset the counters of
|
||||
received and dropped packets or connections after reporting the current values.
|
||||
+
|
||||
An example of the output is:
|
||||
+
|
||||
@@ -915,20 +1084,22 @@ The columns are as follows:
|
||||
. The average interval between NTP packets.
|
||||
. The average interval between NTP packets after limiting the response rate.
|
||||
. Time since the last NTP packet was received
|
||||
. The number of command packets received from the client.
|
||||
. The number of command packets dropped to limit the response rate.
|
||||
. The average interval between command packets.
|
||||
. Time since the last command packet was received.
|
||||
. The number of command packets or NTS-KE connections received/accepted from
|
||||
the client.
|
||||
. The number of command packets or NTS-KE connections dropped to limit the
|
||||
response rate.
|
||||
. The average interval between command packets or NTS-KE connections.
|
||||
. Time since the last command packet or NTS-KE connection was
|
||||
received/accepted.
|
||||
|
||||
[[serverstats]]*serverstats*::
|
||||
The *serverstats* command displays how many valid NTP and command requests
|
||||
*chronyd* as a server received from clients, how many of them were dropped to
|
||||
limit the response rate as configured by the
|
||||
<<chrony.conf.adoc#ratelimit,*ratelimit*>> and
|
||||
<<chrony.conf.adoc#cmdratelimit,*cmdratelimit*>> directives, and how many
|
||||
The *serverstats* command displays how many valid NTP and command requests, and
|
||||
NTS-KE connections, *chronyd* operating as a server received from clients, and
|
||||
how many of them were dropped due to rate limiting. It also displays how many
|
||||
client log records were dropped due to the memory limit configured by the
|
||||
<<chrony.conf.adoc#clientloglimit,*clientloglimit*>> directive. An example of
|
||||
the output is shown below.
|
||||
<<chrony.conf.adoc#clientloglimit,*clientloglimit*>> directive and how many of
|
||||
the NTP requests (from those which were not dropped) were authenticated. An
|
||||
example of the output is shown below.
|
||||
+
|
||||
----
|
||||
NTP packets received : 1598
|
||||
@@ -936,6 +1107,9 @@ NTP packets dropped : 8
|
||||
Command packets received : 19
|
||||
Command packets dropped : 0
|
||||
Client log records dropped : 0
|
||||
NTS-KE connections accepted: 3
|
||||
NTS-KE connections dropped : 0
|
||||
Authenticated NTP packets : 189
|
||||
----
|
||||
|
||||
[[allow]]*allow* [*all*] [_subnet_]::
|
||||
@@ -1121,7 +1295,7 @@ more than 1 second away from the system clock):
|
||||
error).
|
||||
. Save the RTC parameters to the RTC file (specified with the
|
||||
<<chrony.conf.adoc#rtcfile,*rtcfile*>> directive in the configuration file).
|
||||
::
|
||||
{blank}::
|
||||
+
|
||||
The last step is done as a precaution against the computer suffering a power
|
||||
failure before either the daemon exits or the <<writertc,*writertc*>> command
|
||||
@@ -1177,12 +1351,12 @@ also re-reads the server NTS keys if
|
||||
<<chrony.conf.adoc#ntsrotate,automatic rotation>> is disabled in the
|
||||
configuration file.
|
||||
|
||||
[[reset]]*reset*::
|
||||
The *reset* command causes *chronyd* to drop all measurements and switch to the
|
||||
unsynchronised state. This command can help *chronyd* with recovery when the
|
||||
measurements are known to be no longer valid or accurate, e.g. due to moving
|
||||
the computer to a different network, or resuming the computer from a low-power
|
||||
state (which resets the system clock).
|
||||
[[reset]]*reset* *sources*::
|
||||
The *reset sources* command causes *chronyd* to drop all measurements and
|
||||
switch to the unsynchronised state. This command can help *chronyd* with
|
||||
recovery when the measurements are known to be no longer valid or accurate,
|
||||
e.g. due to moving the computer to a different network, or resuming the
|
||||
computer from a low-power state (which resets the system clock).
|
||||
|
||||
[[shutdown]]*shutdown*::
|
||||
The *shutdown* command causes *chronyd* to exit. This is equivalent to sending
|
||||
|
||||
@@ -76,6 +76,12 @@ the log file, syslog, or terminal. The following levels can be specified:
|
||||
0 (informational), 1 (warning), 2 (non-fatal error), and 3 (fatal error). The
|
||||
default value is 0.
|
||||
|
||||
*-p*::
|
||||
When run in this mode, *chronyd* will print the configuration and exit. It will
|
||||
not detach from the terminal. This option can be used to verify the syntax of
|
||||
the configuration and get the whole configuration, even if it is split into
|
||||
multiple files and read by the *include* or *confdir* directive.
|
||||
|
||||
*-q*::
|
||||
When run in this mode, *chronyd* will set the system clock once and exit. It
|
||||
will not detach from the terminal.
|
||||
|
||||
14
doc/faq.adoc
14
doc/faq.adoc
@@ -421,11 +421,17 @@ Perhaps you have a firewall set up in a way that blocks packets on port
|
||||
|
||||
=== I keep getting the error `501 Not authorised`
|
||||
|
||||
Since version 2.2, the `password` command doesn't do anything and `chronyc`
|
||||
needs to run locally under the root or _chrony_ user, which are allowed to
|
||||
access the ``chronyd``'s Unix domain command socket.
|
||||
This error indicates that `chronyc` sent the command to `chronyd` using a UDP
|
||||
socket instead of the Unix domain socket (e.g. _/var/run/chrony/chronyd.sock_),
|
||||
which is required for some commands. For security reasons, only the root and
|
||||
_chrony_ users are allowed to access the socket.
|
||||
|
||||
With older versions, you need to authenticate with the `password` command first
|
||||
It is also possible that the socket doesn't exist. `chronyd` will not create
|
||||
the socket if the directory has a wrong owner or permissions. In this case
|
||||
there should be an error message from `chronyd` in the system log.
|
||||
|
||||
With versions older than 2.2, which don't use the Unix domain socket, you need
|
||||
to authenticate with the `password` command first,
|
||||
or use the `-a` option to authenticate automatically on start. The
|
||||
configuration file needs to specify a file which contains keys (`keyfile`
|
||||
directive) and which key in the key file should be used for `chronyc`
|
||||
|
||||
@@ -25,9 +25,18 @@ rtcsync
|
||||
# Serve time even if not synchronized to a time source.
|
||||
#local stratum 10
|
||||
|
||||
# Require authentication (nts or key option) for all NTP sources.
|
||||
#authselectmode require
|
||||
|
||||
# Specify file containing keys for NTP authentication.
|
||||
#keyfile /etc/chrony.keys
|
||||
|
||||
# Save NTS keys and cookies.
|
||||
ntsdumpdir /var/lib/chrony
|
||||
|
||||
# Insert/delete leap seconds by slewing instead of stepping.
|
||||
#leapsecmode slew
|
||||
|
||||
# Get TAI-UTC offset and leap seconds from the system tz database.
|
||||
#leapsectz right/UTC
|
||||
|
||||
|
||||
@@ -57,6 +57,20 @@
|
||||
|
||||
! maxdrift 100
|
||||
|
||||
# By default, chronyd allows synchronisation to an unauthenticated NTP
|
||||
# source (i.e. specified without the nts and key options) if it agrees with
|
||||
# a majority of authenticated NTP sources, or if no authenticated source is
|
||||
# specified. If you don't want chronyd to ever synchronise to an
|
||||
# unauthenticated NTP source, uncomment the first from the following lines.
|
||||
# If you don't want to synchronise to an unauthenticated NTP source only
|
||||
# when an authenticated source is specified, uncomment the second line.
|
||||
# If you want chronyd to ignore authentication in the source selection,
|
||||
# uncomment the third line.
|
||||
|
||||
! authselectmode require
|
||||
! authselectmode prefer
|
||||
! authselectmode ignore
|
||||
|
||||
#######################################################################
|
||||
### FILENAMES ETC
|
||||
# Chrony likes to keep information about your computer's clock in files.
|
||||
@@ -72,22 +86,37 @@ driftfile /var/lib/chrony/drift
|
||||
|
||||
! keyfile /etc/chrony.keys
|
||||
|
||||
# If you specify an NTP server with the nts option to enable authentication
|
||||
# with the Network Time Security (NTS) mechanism, or enable server NTS with
|
||||
# the ntsservercert and ntsserverkey directives below, the following line will
|
||||
# allow the client/server to save the NTS keys and cookies in order to reduce
|
||||
# the number of key establishments (NTS-KE sessions).
|
||||
|
||||
ntsdumpdir /var/lib/chrony
|
||||
|
||||
# If chronyd is configured to act as an NTP server and you want to enable NTS
|
||||
# for its clients, you will need a TLS certificate and private key. Uncomment
|
||||
# and edit the following lines to specify the locations of the certificate and
|
||||
# key.
|
||||
|
||||
! ntsservercert /etc/.../foo.example.net.crt
|
||||
! ntsserverkey /etc/.../foo.example.net.key
|
||||
|
||||
# chronyd can save the measurement history for the servers to files when
|
||||
# it it exits. This is useful in 2 situations:
|
||||
# it exits. This is useful in 2 situations:
|
||||
#
|
||||
# 1. On Linux, if you stop chronyd and restart it with '-r' (e.g. after
|
||||
# 1. If you stop chronyd and restart it with the '-r' option (e.g. after
|
||||
# an upgrade), the old measurements will still be relevant when chronyd
|
||||
# is restarted. This will reduce the time needed to get accurate
|
||||
# gain/loss measurements, especially with a dial-up link.
|
||||
# gain/loss measurements.
|
||||
#
|
||||
# 2. Again on Linux, if you use the RTC support and start chronyd with
|
||||
# 2. On Linux, if you use the RTC support and start chronyd with
|
||||
# '-r -s' on bootup, measurements from the last boot will still be
|
||||
# useful (the real time clock is used to 'flywheel' chronyd between
|
||||
# boots).
|
||||
#
|
||||
# Enable these two options to use this.
|
||||
# Uncomment the following line to use this.
|
||||
|
||||
! dumponexit
|
||||
! dumpdir /var/lib/chrony
|
||||
|
||||
# chronyd writes its process ID to a file. If you try to start a second
|
||||
@@ -116,6 +145,18 @@ driftfile /var/lib/chrony/drift
|
||||
|
||||
! makestep 1.0 3
|
||||
|
||||
#######################################################################
|
||||
### LEAP SECONDS
|
||||
# A leap second is an occasional one-second correction of the UTC
|
||||
# time scale. By default, chronyd tells the kernel to insert/delete
|
||||
# the leap second, which makes a backward/forward step to correct the
|
||||
# clock for it. As with the makestep directive, this jump can upset
|
||||
# some applications. If you prefer chronyd to make a gradual
|
||||
# correction, causing the clock to be off for a longer time, uncomment
|
||||
# the following line.
|
||||
|
||||
! leapsecmode slew
|
||||
|
||||
#######################################################################
|
||||
### LOGGING
|
||||
# If you want to log information about the time measurements chronyd has
|
||||
@@ -135,8 +176,6 @@ driftfile /var/lib/chrony/drift
|
||||
#######################################################################
|
||||
### ACTING AS AN NTP SERVER
|
||||
# You might want the computer to be an NTP server for other computers.
|
||||
# e.g. you might be running chronyd on a dial-up machine that has a LAN
|
||||
# sitting behind it with several 'satellite' computers on it.
|
||||
#
|
||||
# By default, chronyd does not allow any clients to access it. You need
|
||||
# to explicitly enable access using 'allow' and 'deny' directives.
|
||||
@@ -152,15 +191,6 @@ driftfile /var/lib/chrony/drift
|
||||
# You can have as many allow and deny directives as you need. The order
|
||||
# is unimportant.
|
||||
|
||||
# If you want chronyd to act as an NTP broadcast server, enable and edit
|
||||
# (and maybe copy) the following line. This means that a broadcast
|
||||
# packet is sent to the address 192.168.1.255 every 60 seconds. The
|
||||
# address MUST correspond to the broadcast address of one of the network
|
||||
# interfaces on your machine. If you have multiple network interfaces,
|
||||
# add a broadcast line for each.
|
||||
|
||||
! broadcast 60 192.168.1.255
|
||||
|
||||
# If you want to present your computer's time for others to synchronise
|
||||
# with, even if you don't seem to be synchronised to any NTP servers
|
||||
# yourself, enable the following line. The value 10 may be varied
|
||||
|
||||
43
examples/chrony.nm-dispatcher.dhcp
Normal file
43
examples/chrony.nm-dispatcher.dhcp
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/bin/sh
|
||||
# This is a NetworkManager dispatcher script for chronyd to update
|
||||
# its NTP sources passed from DHCP options. Note that this script is
|
||||
# specific to NetworkManager-dispatcher due to use of the
|
||||
# DHCP4_NTP_SERVERS environment variable.
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
interface=$1
|
||||
action=$2
|
||||
|
||||
chronyc=/usr/bin/chronyc
|
||||
default_server_options=iburst
|
||||
server_dir=/var/run/chrony-dhcp
|
||||
|
||||
dhcp_server_file=$server_dir/$interface.sources
|
||||
# DHCP4_NTP_SERVERS is passed from DHCP options by NetworkManager.
|
||||
nm_dhcp_servers=$DHCP4_NTP_SERVERS
|
||||
|
||||
add_servers_from_dhcp() {
|
||||
rm -f "$dhcp_server_file"
|
||||
for server in $nm_dhcp_servers; do
|
||||
echo "server $server $default_server_options" >> "$dhcp_server_file"
|
||||
done
|
||||
$chronyc reload sources > /dev/null 2>&1 || :
|
||||
}
|
||||
|
||||
clear_servers_from_dhcp() {
|
||||
if [ -f "$dhcp_server_file" ]; then
|
||||
rm -f "$dhcp_server_file"
|
||||
$chronyc reload sources > /dev/null 2>&1 || :
|
||||
fi
|
||||
}
|
||||
|
||||
mkdir -p $server_dir
|
||||
|
||||
if [ "$action" = "up" ] || [ "$action" = "dhcp4-change" ]; then
|
||||
add_servers_from_dhcp
|
||||
elif [ "$action" = "down" ]; then
|
||||
clear_servers_from_dhcp
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -5,11 +5,13 @@
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
chronyc=/usr/bin/chronyc
|
||||
|
||||
# For NetworkManager consider only up/down events
|
||||
[ $# -ge 2 ] && [ "$2" != "up" ] && [ "$2" != "down" ] && exit 0
|
||||
|
||||
# Note: for networkd-dispatcher routable.d ~= on and off.d ~= off
|
||||
|
||||
chronyc onoffline > /dev/null 2>&1
|
||||
$chronyc onoffline > /dev/null 2>&1
|
||||
|
||||
exit 0
|
||||
23
hash.h
23
hash.h
@@ -31,12 +31,25 @@
|
||||
/* length of hash values produced by SHA512 */
|
||||
#define MAX_HASH_LENGTH 64
|
||||
|
||||
extern int HSH_GetHashId(const char *name);
|
||||
typedef enum {
|
||||
HSH_INVALID = 0,
|
||||
HSH_MD5 = 1,
|
||||
HSH_SHA1 = 2,
|
||||
HSH_SHA256 = 3,
|
||||
HSH_SHA384 = 4,
|
||||
HSH_SHA512 = 5,
|
||||
HSH_SHA3_224 = 6,
|
||||
HSH_SHA3_256 = 7,
|
||||
HSH_SHA3_384 = 8,
|
||||
HSH_SHA3_512 = 9,
|
||||
HSH_TIGER = 10,
|
||||
HSH_WHIRLPOOL = 11,
|
||||
} HSH_Algorithm;
|
||||
|
||||
extern unsigned int HSH_Hash(int id,
|
||||
const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len);
|
||||
extern int HSH_GetHashId(HSH_Algorithm algorithm);
|
||||
|
||||
extern int HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
|
||||
unsigned char *out, int out_len);
|
||||
|
||||
extern void HSH_Finalise(void);
|
||||
|
||||
|
||||
@@ -36,20 +36,22 @@
|
||||
static MD5_CTX ctx;
|
||||
|
||||
int
|
||||
HSH_GetHashId(const char *name)
|
||||
HSH_GetHashId(HSH_Algorithm algorithm)
|
||||
{
|
||||
/* only MD5 is supported */
|
||||
if (strcmp(name, "MD5"))
|
||||
if (algorithm != HSH_MD5)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
int
|
||||
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
|
||||
unsigned char *out, int out_len)
|
||||
{
|
||||
if (in1_len < 0 || in2_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, in1, in1_len);
|
||||
if (in2)
|
||||
|
||||
@@ -35,36 +35,36 @@
|
||||
#include "memory.h"
|
||||
|
||||
struct hash {
|
||||
const char *name;
|
||||
const HSH_Algorithm algorithm;
|
||||
const char *int_name;
|
||||
const struct nettle_hash *nettle_hash;
|
||||
void *context;
|
||||
};
|
||||
|
||||
static struct hash hashes[] = {
|
||||
{ "MD5", "md5", NULL, NULL },
|
||||
{ "SHA1", "sha1", NULL, NULL },
|
||||
{ "SHA256", "sha256", NULL, NULL },
|
||||
{ "SHA384", "sha384", NULL, NULL },
|
||||
{ "SHA512", "sha512", NULL, NULL },
|
||||
{ "SHA3-224", "sha3_224", NULL, NULL },
|
||||
{ "SHA3-256", "sha3_256", NULL, NULL },
|
||||
{ "SHA3-384", "sha3_384", NULL, NULL },
|
||||
{ "SHA3-512", "sha3_512", NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
{ HSH_MD5, "md5", NULL, NULL },
|
||||
{ HSH_SHA1, "sha1", NULL, NULL },
|
||||
{ HSH_SHA256, "sha256", NULL, NULL },
|
||||
{ HSH_SHA384, "sha384", NULL, NULL },
|
||||
{ HSH_SHA512, "sha512", NULL, NULL },
|
||||
{ HSH_SHA3_224, "sha3_224", NULL, NULL },
|
||||
{ HSH_SHA3_256, "sha3_256", NULL, NULL },
|
||||
{ HSH_SHA3_384, "sha3_384", NULL, NULL },
|
||||
{ HSH_SHA3_512, "sha3_512", NULL, NULL },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
int
|
||||
HSH_GetHashId(const char *name)
|
||||
HSH_GetHashId(HSH_Algorithm algorithm)
|
||||
{
|
||||
int id, nid;
|
||||
|
||||
for (id = 0; hashes[id].name; id++) {
|
||||
if (!strcmp(name, hashes[id].name))
|
||||
for (id = 0; hashes[id].algorithm != 0; id++) {
|
||||
if (hashes[id].algorithm == algorithm)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hashes[id].name)
|
||||
if (hashes[id].algorithm == 0)
|
||||
return -1;
|
||||
|
||||
if (hashes[id].context)
|
||||
@@ -84,14 +84,16 @@ HSH_GetHashId(const char *name)
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
int
|
||||
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
|
||||
unsigned char *out, int out_len)
|
||||
{
|
||||
const struct nettle_hash *hash;
|
||||
void *context;
|
||||
|
||||
if (in1_len < 0 || in2_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
hash = hashes[id].nettle_hash;
|
||||
context = hashes[id].context;
|
||||
|
||||
@@ -112,7 +114,7 @@ HSH_Finalise(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; hashes[i].name; i++) {
|
||||
for (i = 0; hashes[i].algorithm != 0; i++) {
|
||||
if (hashes[i].context)
|
||||
Free(hashes[i].context);
|
||||
}
|
||||
|
||||
34
hash_nss.c
34
hash_nss.c
@@ -38,30 +38,30 @@ static NSSLOWInitContext *ictx;
|
||||
|
||||
struct hash {
|
||||
HASH_HashType type;
|
||||
const char *name;
|
||||
HSH_Algorithm algorithm;
|
||||
NSSLOWHASHContext *context;
|
||||
};
|
||||
|
||||
static struct hash hashes[] = {
|
||||
{ HASH_AlgMD5, "MD5", NULL },
|
||||
{ HASH_AlgSHA1, "SHA1", NULL },
|
||||
{ HASH_AlgSHA256, "SHA256", NULL },
|
||||
{ HASH_AlgSHA384, "SHA384", NULL },
|
||||
{ HASH_AlgSHA512, "SHA512", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
{ HASH_AlgMD5, HSH_MD5, NULL },
|
||||
{ HASH_AlgSHA1, HSH_SHA1, NULL },
|
||||
{ HASH_AlgSHA256, HSH_SHA256, NULL },
|
||||
{ HASH_AlgSHA384, HSH_SHA384, NULL },
|
||||
{ HASH_AlgSHA512, HSH_SHA512, NULL },
|
||||
{ 0, 0, NULL }
|
||||
};
|
||||
|
||||
int
|
||||
HSH_GetHashId(const char *name)
|
||||
HSH_GetHashId(HSH_Algorithm algorithm)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; hashes[i].name; i++) {
|
||||
if (!strcmp(name, hashes[i].name))
|
||||
for (i = 0; hashes[i].algorithm != 0; i++) {
|
||||
if (hashes[i].algorithm == algorithm)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hashes[i].name)
|
||||
if (hashes[i].algorithm == 0)
|
||||
return -1; /* not found */
|
||||
|
||||
if (!ictx && !(ictx = NSSLOW_Init()))
|
||||
@@ -74,14 +74,16 @@ HSH_GetHashId(const char *name)
|
||||
return i;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
int
|
||||
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
|
||||
unsigned char *out, int out_len)
|
||||
{
|
||||
unsigned char buf[MAX_HASH_LENGTH];
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (in1_len < 0 || in2_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
NSSLOWHASH_Begin(hashes[id].context);
|
||||
NSSLOWHASH_Update(hashes[id].context, in1, in1_len);
|
||||
if (in2)
|
||||
@@ -99,7 +101,7 @@ HSH_Finalise(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; hashes[i].name; i++) {
|
||||
for (i = 0; hashes[i].algorithm != 0; i++) {
|
||||
if (hashes[i].context)
|
||||
NSSLOWHASH_Destroy(hashes[i].context);
|
||||
}
|
||||
|
||||
@@ -32,51 +32,51 @@
|
||||
#include "util.h"
|
||||
|
||||
struct hash {
|
||||
const char *name;
|
||||
HSH_Algorithm algorithm;
|
||||
const char *int_name;
|
||||
const struct ltc_hash_descriptor *desc;
|
||||
};
|
||||
|
||||
static const struct hash hashes[] = {
|
||||
{ "MD5", "md5", &md5_desc },
|
||||
{ HSH_MD5, "md5", &md5_desc },
|
||||
#ifdef LTC_SHA1
|
||||
{ "SHA1", "sha1", &sha1_desc },
|
||||
{ HSH_SHA1, "sha1", &sha1_desc },
|
||||
#endif
|
||||
#ifdef LTC_SHA256
|
||||
{ "SHA256", "sha256", &sha256_desc },
|
||||
{ HSH_SHA256, "sha256", &sha256_desc },
|
||||
#endif
|
||||
#ifdef LTC_SHA384
|
||||
{ "SHA384", "sha384", &sha384_desc },
|
||||
{ HSH_SHA384, "sha384", &sha384_desc },
|
||||
#endif
|
||||
#ifdef LTC_SHA512
|
||||
{ "SHA512", "sha512", &sha512_desc },
|
||||
{ HSH_SHA512, "sha512", &sha512_desc },
|
||||
#endif
|
||||
#ifdef LTC_SHA3
|
||||
{ "SHA3-224", "sha3-224", &sha3_224_desc },
|
||||
{ "SHA3-256", "sha3-256", &sha3_256_desc },
|
||||
{ "SHA3-384", "sha3-384", &sha3_384_desc },
|
||||
{ "SHA3-512", "sha3-512", &sha3_512_desc },
|
||||
{ HSH_SHA3_224, "sha3-224", &sha3_224_desc },
|
||||
{ HSH_SHA3_256, "sha3-256", &sha3_256_desc },
|
||||
{ HSH_SHA3_384, "sha3-384", &sha3_384_desc },
|
||||
{ HSH_SHA3_512, "sha3-512", &sha3_512_desc },
|
||||
#endif
|
||||
#ifdef LTC_TIGER
|
||||
{ "TIGER", "tiger", &tiger_desc },
|
||||
{ HSH_TIGER, "tiger", &tiger_desc },
|
||||
#endif
|
||||
#ifdef LTC_WHIRLPOOL
|
||||
{ "WHIRLPOOL", "whirlpool", &whirlpool_desc },
|
||||
{ HSH_WHIRLPOOL, "whirlpool", &whirlpool_desc },
|
||||
#endif
|
||||
{ NULL, NULL, NULL }
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
int
|
||||
HSH_GetHashId(const char *name)
|
||||
HSH_GetHashId(HSH_Algorithm algorithm)
|
||||
{
|
||||
int i, h;
|
||||
|
||||
for (i = 0; hashes[i].name; i++) {
|
||||
if (!strcmp(name, hashes[i].name))
|
||||
for (i = 0; hashes[i].algorithm != 0; i++) {
|
||||
if (hashes[i].algorithm == algorithm)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hashes[i].name)
|
||||
if (hashes[i].algorithm == 0)
|
||||
return -1; /* not found */
|
||||
|
||||
h = find_hash(hashes[i].int_name);
|
||||
@@ -89,15 +89,17 @@ HSH_GetHashId(const char *name)
|
||||
return find_hash(hashes[i].int_name);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
int
|
||||
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
|
||||
unsigned char *out, int out_len)
|
||||
{
|
||||
unsigned char buf[MAX_HASH_LENGTH];
|
||||
unsigned long len;
|
||||
int r;
|
||||
|
||||
if (in1_len < 0 || in2_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
len = sizeof (buf);
|
||||
if (in2)
|
||||
r = hash_memory_multi(id, buf, &len,
|
||||
|
||||
121
keys.c
121
keys.c
@@ -50,16 +50,16 @@ typedef enum {
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
int type;
|
||||
int length;
|
||||
KeyClass class;
|
||||
union {
|
||||
struct {
|
||||
unsigned char *value;
|
||||
int length;
|
||||
int hash_id;
|
||||
} ntp_mac;
|
||||
CMC_Instance cmac;
|
||||
} data;
|
||||
int auth_delay;
|
||||
} Key;
|
||||
|
||||
static ARR_Instance keys;
|
||||
@@ -121,38 +121,6 @@ get_key(unsigned int index)
|
||||
return ((Key *)ARR_GetElements(keys)) + index;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
determine_hash_delay(uint32_t key_id)
|
||||
{
|
||||
NTP_Packet pkt;
|
||||
struct timespec before, after;
|
||||
double diff, min_diff;
|
||||
int i, nsecs;
|
||||
|
||||
memset(&pkt, 0, sizeof (pkt));
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
LCL_ReadRawTime(&before);
|
||||
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_HEADER_LENGTH,
|
||||
(unsigned char *)&pkt + NTP_HEADER_LENGTH,
|
||||
sizeof (pkt) - NTP_HEADER_LENGTH);
|
||||
LCL_ReadRawTime(&after);
|
||||
|
||||
diff = UTI_DiffTimespecsToDouble(&after, &before);
|
||||
|
||||
if (i == 0 || min_diff > diff)
|
||||
min_diff = diff;
|
||||
}
|
||||
|
||||
nsecs = 1.0e9 * min_diff;
|
||||
|
||||
DEBUG_LOG("authentication delay for key %"PRIu32": %d nsecs", key_id, nsecs);
|
||||
|
||||
return nsecs;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Decode key encoded in ASCII or HEX */
|
||||
|
||||
@@ -201,6 +169,8 @@ KEY_Reload(void)
|
||||
FILE *in;
|
||||
char line[2048], *key_file, *key_value;
|
||||
const char *key_type;
|
||||
HSH_Algorithm hash_algorithm;
|
||||
CMC_Algorithm cmac_algorithm;
|
||||
int hash_id;
|
||||
Key key;
|
||||
|
||||
@@ -238,27 +208,40 @@ KEY_Reload(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
hash_id = HSH_GetHashId(key_type);
|
||||
cmac_key_length = CMC_GetKeyLength(key_type);
|
||||
hash_algorithm = UTI_HashNameToAlgorithm(key_type);
|
||||
cmac_algorithm = UTI_CmacNameToAlgorithm(key_type);
|
||||
|
||||
if (hash_id >= 0) {
|
||||
if (hash_algorithm != 0) {
|
||||
hash_id = HSH_GetHashId(hash_algorithm);
|
||||
if (hash_id < 0) {
|
||||
LOG(LOGS_WARN, "Unsupported %s in key %"PRIu32, "hash function", key.id);
|
||||
continue;
|
||||
}
|
||||
key.class = NTP_MAC;
|
||||
key.type = hash_algorithm;
|
||||
key.length = key_length;
|
||||
key.data.ntp_mac.value = MallocArray(unsigned char, key_length);
|
||||
memcpy(key.data.ntp_mac.value, key_value, key_length);
|
||||
key.data.ntp_mac.length = key_length;
|
||||
key.data.ntp_mac.hash_id = hash_id;
|
||||
} else if (cmac_key_length > 0) {
|
||||
if (cmac_key_length != key_length) {
|
||||
} else if (cmac_algorithm != 0) {
|
||||
cmac_key_length = CMC_GetKeyLength(cmac_algorithm);
|
||||
if (cmac_key_length == 0) {
|
||||
LOG(LOGS_WARN, "Unsupported %s in key %"PRIu32, "cipher", key.id);
|
||||
continue;
|
||||
} else if (cmac_key_length != key_length) {
|
||||
LOG(LOGS_WARN, "Invalid length of %s key %"PRIu32" (expected %u bits)",
|
||||
key_type, key.id, 8 * cmac_key_length);
|
||||
continue;
|
||||
}
|
||||
|
||||
key.class = CMAC;
|
||||
key.data.cmac = CMC_CreateInstance(key_type, (unsigned char *)key_value, key_length);
|
||||
key.type = cmac_algorithm;
|
||||
key.length = key_length;
|
||||
key.data.cmac = CMC_CreateInstance(cmac_algorithm, (unsigned char *)key_value,
|
||||
key_length);
|
||||
assert(key.data.cmac);
|
||||
} else {
|
||||
LOG(LOGS_WARN, "Unknown hash function or cipher in key %"PRIu32, key.id);
|
||||
LOG(LOGS_WARN, "Invalid type in key %"PRIu32, key.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -280,9 +263,6 @@ KEY_Reload(void)
|
||||
|
||||
/* Erase any passwords from stack */
|
||||
memset(line, 0, sizeof (line));
|
||||
|
||||
for (i = 0; i < ARR_GetSize(keys); i++)
|
||||
get_key(i)->auth_delay = determine_hash_delay(get_key(i)->id);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -338,21 +318,6 @@ KEY_KeyKnown(uint32_t key_id)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_GetAuthDelay(uint32_t key_id)
|
||||
{
|
||||
Key *key;
|
||||
|
||||
key = get_key_by_id(key_id);
|
||||
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
return key->auth_delay;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_GetAuthLength(uint32_t key_id)
|
||||
{
|
||||
@@ -387,24 +352,36 @@ KEY_CheckKeyLength(uint32_t key_id)
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
switch (key->class) {
|
||||
case NTP_MAC:
|
||||
return key->data.ntp_mac.length >= MIN_SECURE_KEY_LENGTH;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return key->length >= MIN_SECURE_KEY_LENGTH;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_GetKeyInfo(uint32_t key_id, int *type, int *bits)
|
||||
{
|
||||
Key *key;
|
||||
|
||||
key = get_key_by_id(key_id);
|
||||
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
*type = key->type;
|
||||
*bits = 8 * key->length;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
generate_auth(Key *key, const unsigned char *data, int data_len,
|
||||
unsigned char *auth, int auth_len)
|
||||
generate_auth(Key *key, const void *data, int data_len, unsigned char *auth, int auth_len)
|
||||
{
|
||||
switch (key->class) {
|
||||
case NTP_MAC:
|
||||
return HSH_Hash(key->data.ntp_mac.hash_id, key->data.ntp_mac.value,
|
||||
key->data.ntp_mac.length, data, data_len, auth, auth_len);
|
||||
key->length, data, data_len, auth, auth_len);
|
||||
case CMAC:
|
||||
return CMC_Hash(key->data.cmac, data, data_len, auth, auth_len);
|
||||
default:
|
||||
@@ -415,7 +392,7 @@ generate_auth(Key *key, const unsigned char *data, int data_len,
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_auth(Key *key, const unsigned char *data, int data_len,
|
||||
check_auth(Key *key, const void *data, int data_len,
|
||||
const unsigned char *auth, int auth_len, int trunc_len)
|
||||
{
|
||||
unsigned char buf[MAX_HASH_LENGTH];
|
||||
@@ -429,7 +406,7 @@ check_auth(Key *key, const unsigned char *data, int data_len,
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_GenerateAuth(uint32_t key_id, const unsigned char *data, int data_len,
|
||||
KEY_GenerateAuth(uint32_t key_id, const void *data, int data_len,
|
||||
unsigned char *auth, int auth_len)
|
||||
{
|
||||
Key *key;
|
||||
@@ -445,7 +422,7 @@ KEY_GenerateAuth(uint32_t key_id, const unsigned char *data, int data_len,
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_CheckAuth(uint32_t key_id, const unsigned char *data, int data_len,
|
||||
KEY_CheckAuth(uint32_t key_id, const void *data, int data_len,
|
||||
const unsigned char *auth, int auth_len, int trunc_len)
|
||||
{
|
||||
Key *key;
|
||||
|
||||
9
keys.h
9
keys.h
@@ -34,15 +34,14 @@ extern void KEY_Finalise(void);
|
||||
|
||||
extern void KEY_Reload(void);
|
||||
|
||||
extern int KEY_GetKey(uint32_t key_id, char **key, int *len);
|
||||
extern int KEY_KeyKnown(uint32_t key_id);
|
||||
extern int KEY_GetAuthDelay(uint32_t key_id);
|
||||
extern int KEY_GetAuthLength(uint32_t key_id);
|
||||
extern int KEY_CheckKeyLength(uint32_t key_id);
|
||||
extern int KEY_GetKeyInfo(uint32_t key_id, int *type, int *bits);
|
||||
|
||||
extern int KEY_GenerateAuth(uint32_t key_id, const unsigned char *data,
|
||||
int data_len, unsigned char *auth, int auth_len);
|
||||
extern int KEY_CheckAuth(uint32_t key_id, const unsigned char *data, int data_len,
|
||||
extern int KEY_GenerateAuth(uint32_t key_id, const void *data, int data_len,
|
||||
unsigned char *auth, int auth_len);
|
||||
extern int KEY_CheckAuth(uint32_t key_id, const void *data, int data_len,
|
||||
const unsigned char *auth, int auth_len, int trunc_len);
|
||||
|
||||
#endif /* GOT_KEYS_H */
|
||||
|
||||
12
local.c
12
local.c
@@ -185,13 +185,11 @@ LCL_Initialise(void)
|
||||
void
|
||||
LCL_Finalise(void)
|
||||
{
|
||||
while (change_list.next != &change_list)
|
||||
LCL_RemoveParameterChangeHandler(change_list.next->handler,
|
||||
change_list.next->anything);
|
||||
|
||||
while (dispersion_notify_list.next != &dispersion_notify_list)
|
||||
LCL_RemoveDispersionNotifyHandler(dispersion_notify_list.next->handler,
|
||||
dispersion_notify_list.next->anything);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
35
logging.c
35
logging.c
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
|
||||
/* This is used by DEBUG_LOG macro */
|
||||
@@ -61,12 +62,16 @@ static int n_filelogs = 0;
|
||||
|
||||
static struct LogFile logfiles[MAX_FILELOGS];
|
||||
|
||||
/* Global prefix for debug messages */
|
||||
static char *debug_prefix;
|
||||
|
||||
/* ================================================== */
|
||||
/* Init function */
|
||||
|
||||
void
|
||||
LOG_Initialise(void)
|
||||
{
|
||||
debug_prefix = Strdup("");
|
||||
initialised = 1;
|
||||
LOG_OpenFileLog(NULL);
|
||||
}
|
||||
@@ -85,6 +90,8 @@ LOG_Finalise(void)
|
||||
|
||||
LOG_CycleLogFiles();
|
||||
|
||||
Free(debug_prefix);
|
||||
|
||||
initialised = 0;
|
||||
}
|
||||
|
||||
@@ -132,6 +139,8 @@ void LOG_Message(LOG_Severity severity,
|
||||
time_t t;
|
||||
struct tm *tm;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
if (!system_log && file_log && severity >= log_min_severity) {
|
||||
/* Don't clutter up syslog with timestamps and internal debugging info */
|
||||
time(&t);
|
||||
@@ -142,7 +151,7 @@ void LOG_Message(LOG_Severity severity,
|
||||
}
|
||||
#if DEBUG > 0
|
||||
if (log_min_severity <= LOGS_DEBUG)
|
||||
fprintf(file_log, "%s:%d:(%s) ", filename, line_number, function_name);
|
||||
fprintf(file_log, "%s%s:%d:(%s) ", debug_prefix, filename, line_number, function_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -220,6 +229,23 @@ void LOG_SetMinSeverity(LOG_Severity severity)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
LOG_Severity
|
||||
LOG_GetMinSeverity(void)
|
||||
{
|
||||
return log_min_severity;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_SetDebugPrefix(const char *prefix)
|
||||
{
|
||||
Free(debug_prefix);
|
||||
debug_prefix = Strdup(prefix);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_SetParentFd(int fd)
|
||||
{
|
||||
@@ -243,7 +269,10 @@ LOG_CloseParentFd()
|
||||
LOG_FileID
|
||||
LOG_FileOpen(const char *name, const char *banner)
|
||||
{
|
||||
assert(n_filelogs < MAX_FILELOGS);
|
||||
if (n_filelogs >= MAX_FILELOGS) {
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
logfiles[n_filelogs].name = name;
|
||||
logfiles[n_filelogs].banner = banner;
|
||||
@@ -267,7 +296,7 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
|
||||
if (!logfiles[id].file) {
|
||||
char *logdir = CNF_GetLogDir();
|
||||
|
||||
if (logdir[0] == '\0') {
|
||||
if (!logdir) {
|
||||
LOG(LOGS_WARN, "logdir not specified");
|
||||
logfiles[id].name = NULL;
|
||||
return;
|
||||
|
||||
@@ -97,6 +97,12 @@ extern void LOG_Message(LOG_Severity severity, const char *format, ...);
|
||||
prefixed with the filename, line number, and function name. */
|
||||
extern void LOG_SetMinSeverity(LOG_Severity severity);
|
||||
|
||||
/* Get the minimum severity */
|
||||
extern LOG_Severity LOG_GetMinSeverity(void);
|
||||
|
||||
/* Set a prefix for debug messages */
|
||||
extern void LOG_SetDebugPrefix(const char *prefix);
|
||||
|
||||
/* Log messages to a file instead of stderr, or stderr again if NULL */
|
||||
extern void LOG_OpenFileLog(const char *log_file);
|
||||
|
||||
|
||||
47
main.c
47
main.c
@@ -38,7 +38,6 @@
|
||||
#include "ntp_signd.h"
|
||||
#include "ntp_sources.h"
|
||||
#include "ntp_core.h"
|
||||
#include "nts_ke_client.h"
|
||||
#include "nts_ke_server.h"
|
||||
#include "nts_ntp_server.h"
|
||||
#include "socket.h"
|
||||
@@ -91,7 +90,7 @@ delete_pidfile(void)
|
||||
{
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
|
||||
if (!pidfile[0])
|
||||
if (!pidfile)
|
||||
return;
|
||||
|
||||
if (!UTI_RemoveFile(NULL, pidfile, NULL))
|
||||
@@ -105,9 +104,7 @@ MAI_CleanupAndExit(void)
|
||||
{
|
||||
if (!initialised) exit(exit_status);
|
||||
|
||||
if (CNF_GetDumpDir()[0] != '\0') {
|
||||
SRC_DumpSources();
|
||||
}
|
||||
SRC_DumpSources();
|
||||
|
||||
/* Don't update clock when removing sources */
|
||||
REF_SetMode(REF_ModeIgnore);
|
||||
@@ -116,7 +113,6 @@ MAI_CleanupAndExit(void)
|
||||
TMC_Finalise();
|
||||
MNL_Finalise();
|
||||
CLG_Finalise();
|
||||
NKC_Finalise();
|
||||
NKS_Finalise();
|
||||
NNS_Finalise();
|
||||
NSD_Finalise();
|
||||
@@ -125,13 +121,15 @@ MAI_CleanupAndExit(void)
|
||||
NCR_Finalise();
|
||||
NIO_Finalise();
|
||||
CAM_Finalise();
|
||||
SCK_Finalise();
|
||||
|
||||
KEY_Finalise();
|
||||
RCL_Finalise();
|
||||
SRC_Finalise();
|
||||
REF_Finalise();
|
||||
RTC_Finalise();
|
||||
SYS_Finalise();
|
||||
|
||||
SCK_Finalise();
|
||||
SCH_Finalise();
|
||||
LCL_Finalise();
|
||||
PRV_Finalise();
|
||||
@@ -150,7 +148,6 @@ MAI_CleanupAndExit(void)
|
||||
static void
|
||||
signal_cleanup(int x)
|
||||
{
|
||||
if (!initialised) exit(0);
|
||||
SCH_QuitProgram();
|
||||
}
|
||||
|
||||
@@ -261,7 +258,7 @@ check_pidfile(void)
|
||||
FILE *in;
|
||||
int pid, count;
|
||||
|
||||
if (!pidfile[0])
|
||||
if (!pidfile)
|
||||
return;
|
||||
|
||||
in = UTI_OpenFile(NULL, pidfile, NULL, 'r', 0);
|
||||
@@ -289,7 +286,7 @@ write_pidfile(void)
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
FILE *out;
|
||||
|
||||
if (!pidfile[0])
|
||||
if (!pidfile)
|
||||
return;
|
||||
|
||||
out = UTI_OpenFile(NULL, pidfile, NULL, 'W', 0644);
|
||||
@@ -377,7 +374,7 @@ go_daemon(void)
|
||||
static void
|
||||
print_help(const char *progname)
|
||||
{
|
||||
printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-t TIMEOUT] [-f FILE|COMMAND...]\n",
|
||||
printf("Usage: %s [-4|-6] [-n|-d] [-p|-q|-Q] [-r] [-R] [-s] [-t TIMEOUT] [-f FILE|COMMAND...]\n",
|
||||
progname);
|
||||
}
|
||||
|
||||
@@ -414,7 +411,7 @@ int main
|
||||
int do_init_rtc = 0, restarted = 0, client_only = 0, timeout = -1;
|
||||
int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
|
||||
int clock_control = 1, system_log = 1, log_severity = LOGS_INFO;
|
||||
int config_args = 0;
|
||||
int config_args = 0, print_config = 0;
|
||||
|
||||
do_platform_checks();
|
||||
|
||||
@@ -434,7 +431,7 @@ int main
|
||||
optind = 1;
|
||||
|
||||
/* Parse short command-line options */
|
||||
while ((opt = getopt(argc, argv, "46df:F:hl:L:mnP:qQrRst:u:vx")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "46df:F:hl:L:mnpP:qQrRst:u:vx")) != -1) {
|
||||
switch (opt) {
|
||||
case '4':
|
||||
case '6':
|
||||
@@ -463,6 +460,12 @@ int main
|
||||
case 'n':
|
||||
nofork = 1;
|
||||
break;
|
||||
case 'p':
|
||||
print_config = 1;
|
||||
client_only = 1;
|
||||
nofork = 1;
|
||||
system_log = 0;
|
||||
break;
|
||||
case 'P':
|
||||
sched_priority = parse_int_arg(optarg);
|
||||
break;
|
||||
@@ -527,6 +530,8 @@ int main
|
||||
DNS_SetAddressFamily(address_family);
|
||||
|
||||
CNF_Initialise(restarted, client_only);
|
||||
if (print_config)
|
||||
CNF_EnablePrint();
|
||||
|
||||
/* Parse the config file or the remaining command line arguments */
|
||||
config_args = argc - optind;
|
||||
@@ -537,6 +542,9 @@ int main
|
||||
CNF_ParseLine(NULL, config_args + optind - argc + 1, argv[optind]);
|
||||
}
|
||||
|
||||
if (print_config)
|
||||
return 0;
|
||||
|
||||
/* Check whether another chronyd may already be running */
|
||||
check_pidfile();
|
||||
|
||||
@@ -556,16 +564,20 @@ int main
|
||||
PRV_Initialise();
|
||||
LCL_Initialise();
|
||||
SCH_Initialise();
|
||||
SCK_Initialise(address_family);
|
||||
|
||||
/* Start helper processes if needed */
|
||||
NKS_PreInitialise(pw->pw_uid, pw->pw_gid, scfilter_level);
|
||||
|
||||
SYS_Initialise(clock_control);
|
||||
RTC_Initialise(do_init_rtc);
|
||||
SRC_Initialise();
|
||||
RCL_Initialise();
|
||||
KEY_Initialise();
|
||||
SCK_Initialise();
|
||||
|
||||
/* Open privileged ports before dropping root */
|
||||
CAM_Initialise(address_family);
|
||||
NIO_Initialise(address_family);
|
||||
CAM_Initialise();
|
||||
NIO_Initialise();
|
||||
NCR_Initialise();
|
||||
CNF_SetupAccessRestrictions();
|
||||
|
||||
@@ -590,8 +602,7 @@ int main
|
||||
NSR_Initialise();
|
||||
NSD_Initialise();
|
||||
NNS_Initialise();
|
||||
NKS_Initialise(scfilter_level);
|
||||
NKC_Initialise();
|
||||
NKS_Initialise();
|
||||
CLG_Initialise();
|
||||
MNL_Initialise();
|
||||
TMC_Initialise();
|
||||
|
||||
1
manual.c
1
manual.c
@@ -92,6 +92,7 @@ MNL_Initialise(void)
|
||||
void
|
||||
MNL_Finalise(void)
|
||||
{
|
||||
LCL_RemoveParameterChangeHandler(slew_samples, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -95,6 +95,9 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
|
||||
case AF_INET6:
|
||||
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET6)
|
||||
continue;
|
||||
/* Don't return an address that would lose a scope ID */
|
||||
if (((struct sockaddr_in6 *)ai->ai_addr)->sin6_scope_id != 0)
|
||||
continue;
|
||||
ip_addrs[i].family = IPADDR_INET6;
|
||||
memcpy(&ip_addrs[i].addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr,
|
||||
sizeof (ip_addrs->addr.in6));
|
||||
|
||||
95
ntp_auth.c
95
ntp_auth.c
@@ -55,20 +55,29 @@ generate_symmetric_auth(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *inf
|
||||
{
|
||||
int auth_len, max_auth_len;
|
||||
|
||||
if (info->length + NTP_MIN_MAC_LENGTH > sizeof (*packet)) {
|
||||
DEBUG_LOG("Packet too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Truncate long MACs in NTPv4 packets to allow deterministic parsing
|
||||
of extension fields (RFC 7822) */
|
||||
max_auth_len = (info->version == 4 ? NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH) - 4;
|
||||
max_auth_len = MIN(max_auth_len, sizeof (NTP_Packet) - info->length - 4);
|
||||
max_auth_len = MIN(max_auth_len, sizeof (*packet) - info->length - 4);
|
||||
|
||||
auth_len = KEY_GenerateAuth(key_id, (unsigned char *)packet, info->length,
|
||||
auth_len = KEY_GenerateAuth(key_id, packet, info->length,
|
||||
(unsigned char *)packet + info->length + 4, max_auth_len);
|
||||
if (!auth_len) {
|
||||
if (auth_len < NTP_MIN_MAC_LENGTH - 4) {
|
||||
DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*(uint32_t *)((unsigned char *)packet + info->length) = htonl(key_id);
|
||||
info->length += 4 + auth_len;
|
||||
|
||||
info->auth.mac.start = info->length;
|
||||
info->auth.mac.length = 4 + auth_len;
|
||||
info->auth.mac.key_id = key_id;
|
||||
info->length += info->auth.mac.length;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -86,7 +95,7 @@ check_symmetric_auth(NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
trunc_len = info->version == 4 && info->auth.mac.length <= NTP_MAX_V4_MAC_LENGTH ?
|
||||
NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH;
|
||||
|
||||
if (!KEY_CheckAuth(info->auth.mac.key_id, (void *)packet, info->auth.mac.start,
|
||||
if (!KEY_CheckAuth(info->auth.mac.key_id, packet, info->auth.mac.start,
|
||||
(unsigned char *)packet + info->auth.mac.start + 4,
|
||||
info->auth.mac.length - 4, trunc_len - 4))
|
||||
return 0;
|
||||
@@ -96,31 +105,13 @@ check_symmetric_auth(NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
adjust_timestamp(NTP_AuthMode mode, uint32_t key_id, struct timespec *ts)
|
||||
{
|
||||
switch (mode) {
|
||||
case NTP_AUTH_SYMMETRIC:
|
||||
ts->tv_nsec += KEY_GetAuthDelay(key_id);
|
||||
UTI_NormaliseTimespec(ts);
|
||||
break;
|
||||
case NTP_AUTH_MSSNTP:
|
||||
ts->tv_nsec += NSD_GetAuthDelay(key_id);
|
||||
UTI_NormaliseTimespec(ts);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
is_zero_data(unsigned char *data, int length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
if (data[i])
|
||||
if (data[i] != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -230,14 +221,6 @@ NAU_PrepareRequestAuth(NAU_Instance instance)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NAU_AdjustRequestTimestamp(NAU_Instance instance, struct timespec *ts)
|
||||
{
|
||||
adjust_timestamp(instance->mode, instance->key_id, ts);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request, NTP_PacketInfo *info)
|
||||
{
|
||||
@@ -256,6 +239,8 @@ NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request, NTP_PacketIn
|
||||
assert(0);
|
||||
}
|
||||
|
||||
info->auth.mode = instance->mode;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -277,6 +262,8 @@ NAU_ParsePacket(NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
if (remainder <= 0)
|
||||
return 1;
|
||||
|
||||
assert(remainder % 4 == 0);
|
||||
|
||||
/* In NTPv3 and older packets don't have extension fields. Anything after
|
||||
the header is assumed to be a MAC. */
|
||||
if (info->version <= 3) {
|
||||
@@ -287,7 +274,7 @@ NAU_ParsePacket(NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
|
||||
/* Check if it is an MS-SNTP authenticator field or extended authenticator
|
||||
field with zeroes as digest */
|
||||
if (info->version == 3 && info->auth.mac.key_id) {
|
||||
if (info->version == 3 && info->auth.mac.key_id != 0) {
|
||||
if (remainder == 20 && is_zero_data(data + parsed + 4, remainder - 4))
|
||||
info->auth.mode = NTP_AUTH_MSSNTP;
|
||||
else if (remainder == 72 && is_zero_data(data + parsed + 8, remainder - 8))
|
||||
@@ -321,7 +308,7 @@ NAU_ParsePacket(NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
if (parsed == NTP_HEADER_LENGTH &&
|
||||
remainder > NTP_MAX_V4_MAC_LENGTH && remainder <= NTP_MAX_MAC_LENGTH &&
|
||||
KEY_CheckAuth(ntohl(*(uint32_t *)(data + parsed)), data, parsed,
|
||||
(void *)(data + parsed + 4), remainder - 4, NTP_MAX_MAC_LENGTH - 4))
|
||||
data + parsed + 4, remainder - 4, NTP_MAX_MAC_LENGTH - 4))
|
||||
break;
|
||||
|
||||
/* Check if this is a valid NTPv4 extension field and skip it */
|
||||
@@ -331,7 +318,7 @@ NAU_ParsePacket(NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(ef_length > 0);
|
||||
assert(ef_length > 0 && ef_length % 4 == 0);
|
||||
|
||||
switch (ef_type) {
|
||||
case NTP_EF_NTS_UNIQUE_IDENTIFIER:
|
||||
@@ -384,6 +371,9 @@ NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info, uint32_t *kod)
|
||||
case NTP_AUTH_MSSNTP:
|
||||
/* MS-SNTP requests are not authenticated */
|
||||
break;
|
||||
case NTP_AUTH_MSSNTP_EXT:
|
||||
/* Not supported yet */
|
||||
return 0;
|
||||
case NTP_AUTH_NTS:
|
||||
if (!NNS_CheckRequestAuth(request, info, kod))
|
||||
return 0;
|
||||
@@ -397,14 +387,6 @@ NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info, uint32_t *kod)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NAU_AdjustResponseTimestamp(NTP_Packet *request, NTP_PacketInfo *info, struct timespec *ts)
|
||||
{
|
||||
adjust_timestamp(info->auth.mode, info->auth.mac.key_id, ts);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NAU_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *request_info,
|
||||
NTP_Packet *response, NTP_PacketInfo *response_info,
|
||||
@@ -434,6 +416,8 @@ NAU_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *request_info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
response_info->auth.mode = request_info->auth.mode;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -498,3 +482,28 @@ NAU_DumpData(NAU_Instance instance)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NAU_GetReport(NAU_Instance instance, RPT_AuthReport *report)
|
||||
{
|
||||
memset(report, 0, sizeof (*report));
|
||||
|
||||
report->mode = instance->mode;
|
||||
report->last_ke_ago = -1;
|
||||
|
||||
switch (instance->mode) {
|
||||
case NTP_AUTH_NONE:
|
||||
break;
|
||||
case NTP_AUTH_SYMMETRIC:
|
||||
report->key_id = instance->key_id;
|
||||
KEY_GetKeyInfo(instance->key_id, &report->key_type, &report->key_length);
|
||||
break;
|
||||
case NTP_AUTH_NTS:
|
||||
NNC_GetReport(instance->nts, report);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
13
ntp_auth.h
13
ntp_auth.h
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "addressing.h"
|
||||
#include "ntp.h"
|
||||
#include "reports.h"
|
||||
|
||||
typedef struct NAU_Instance_Record *NAU_Instance;
|
||||
|
||||
@@ -50,10 +51,6 @@ extern int NAU_GetSuggestedNtpVersion(NAU_Instance instance);
|
||||
/* Perform operations necessary for NAU_GenerateRequestAuth() */
|
||||
extern int NAU_PrepareRequestAuth(NAU_Instance instance);
|
||||
|
||||
/* Adjust a transmit timestamp for an estimated minimum time it takes to call
|
||||
NAU_GenerateRequestAuth() */
|
||||
extern void NAU_AdjustRequestTimestamp(NAU_Instance instance, struct timespec *ts);
|
||||
|
||||
/* Extend a request with data required by the authentication mode */
|
||||
extern int NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request,
|
||||
NTP_PacketInfo *info);
|
||||
@@ -65,11 +62,6 @@ extern int NAU_ParsePacket(NTP_Packet *packet, NTP_PacketInfo *info);
|
||||
kod code is returned, a KoD response should be sent back. */
|
||||
extern int NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info, uint32_t *kod);
|
||||
|
||||
/* Adjust a transmit timestamp for an estimated minimum time it takes to call
|
||||
NAU_GenerateResponseAuth() */
|
||||
extern void NAU_AdjustResponseTimestamp(NTP_Packet *request, NTP_PacketInfo *info,
|
||||
struct timespec *ts);
|
||||
|
||||
/* Extend a response with data required by the authentication mode. This
|
||||
function can be called only if the previous call of NAU_CheckRequestAuth()
|
||||
was on the same request. */
|
||||
@@ -89,4 +81,7 @@ extern void NAU_ChangeAddress(NAU_Instance instance, IPAddr *address);
|
||||
/* Save authentication-specific data to speed up the next start */
|
||||
extern void NAU_DumpData(NAU_Instance instance);
|
||||
|
||||
/* Provide a report about the current authentication state */
|
||||
extern void NAU_GetReport(NAU_Instance instance, RPT_AuthReport *report);
|
||||
|
||||
#endif
|
||||
|
||||
114
ntp_core.c
114
ntp_core.c
@@ -78,6 +78,7 @@ struct NCR_Instance_Record {
|
||||
SCH_TimeoutID tx_timeout_id; /* Timeout ID for next transmission */
|
||||
int tx_suspended; /* Boolean indicating we can't transmit yet */
|
||||
|
||||
int auto_iburst; /* If 1, initiate a burst when going online */
|
||||
int auto_burst; /* If 1, initiate a burst on each poll */
|
||||
int auto_offline; /* If 1, automatically go offline when requests
|
||||
cannot be sent */
|
||||
@@ -297,6 +298,7 @@ static void transmit_timeout(void *arg);
|
||||
static double get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx);
|
||||
static double get_separation(int poll);
|
||||
static int parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info);
|
||||
static void set_connectivity(NCR_Instance inst, SRC_Connectivity connectivity);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -555,6 +557,7 @@ NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
|
||||
result->max_delay_ratio = CLAMP(0.0, params->max_delay_ratio, MAX_MAXDELAYRATIO);
|
||||
result->max_delay_dev_ratio = CLAMP(0.0, params->max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
|
||||
result->offset_correction = params->offset;
|
||||
result->auto_iburst = params->iburst;
|
||||
result->auto_burst = params->burst;
|
||||
result->auto_offline = params->auto_offline;
|
||||
result->poll_target = params->poll_target;
|
||||
@@ -582,8 +585,8 @@ NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
|
||||
|
||||
/* Create a source instance for this NTP source */
|
||||
result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr),
|
||||
SRC_NTP, params->sel_options,
|
||||
&result->remote_addr.ip_addr,
|
||||
SRC_NTP, NAU_IsAuthEnabled(result->auth),
|
||||
params->sel_options, &result->remote_addr.ip_addr,
|
||||
params->min_samples, params->max_samples,
|
||||
params->min_delay, params->asymmetry);
|
||||
|
||||
@@ -596,9 +599,7 @@ NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
|
||||
result->rx_timeout_id = 0;
|
||||
result->tx_timeout_id = 0;
|
||||
result->tx_suspended = 1;
|
||||
result->opmode = params->connectivity == SRC_ONLINE ||
|
||||
(params->connectivity == SRC_MAYBE_ONLINE &&
|
||||
NIO_IsServerConnectable(remote_addr)) ? MD_ONLINE : MD_OFFLINE;
|
||||
result->opmode = MD_OFFLINE;
|
||||
result->local_poll = result->minpoll;
|
||||
result->poll_score = 0.0;
|
||||
zero_local_timestamp(&result->local_tx);
|
||||
@@ -608,9 +609,7 @@ NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
|
||||
|
||||
NCR_ResetInstance(result);
|
||||
|
||||
if (params->iburst) {
|
||||
NCR_InitiateSampleBurst(result, IBURST_GOOD_SAMPLES, IBURST_TOTAL_SAMPLES);
|
||||
}
|
||||
set_connectivity(result, params->connectivity);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -962,6 +961,10 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
smooth_time = 0;
|
||||
smooth_offset = 0.0;
|
||||
|
||||
/* Get an initial transmit timestamp. A more accurate timestamp will be
|
||||
taken later in this function. */
|
||||
SCH_GetLastEventTime(&local_transmit, NULL, NULL);
|
||||
|
||||
if (my_mode == MODE_CLIENT) {
|
||||
/* Don't reveal local time or state of the clock in client packets */
|
||||
precision = 32;
|
||||
@@ -969,10 +972,6 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
our_root_delay = our_root_dispersion = 0.0;
|
||||
UTI_ZeroTimespec(&our_ref_time);
|
||||
} else {
|
||||
/* This is accurate enough and cheaper than calling LCL_ReadCookedTime.
|
||||
A more accurate timestamp will be taken later in this function. */
|
||||
SCH_GetLastEventTime(&local_transmit, NULL, NULL);
|
||||
|
||||
REF_GetReferenceParams(&local_transmit,
|
||||
&are_we_synchronised, &leap_status,
|
||||
&our_stratum,
|
||||
@@ -1018,12 +1017,8 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
|
||||
message.poll = my_poll;
|
||||
message.precision = precision;
|
||||
|
||||
/* If we're sending a client mode packet and we aren't synchronized yet,
|
||||
we might have to set up artificial values for some of these parameters */
|
||||
message.root_delay = UTI_DoubleToNtp32(our_root_delay);
|
||||
message.root_dispersion = UTI_DoubleToNtp32(our_root_dispersion);
|
||||
|
||||
message.reference_id = htonl(our_ref_id);
|
||||
|
||||
/* Now fill in timestamps */
|
||||
@@ -1063,20 +1058,13 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
/* Prepare random bits which will be added to the transmit timestamp */
|
||||
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
|
||||
|
||||
/* Transmit - this our local time right now! Also, we might need to
|
||||
store this for our own use later, next time we receive a message
|
||||
from the source we're sending to now. */
|
||||
LCL_ReadCookedTime(&local_transmit, &local_transmit_err);
|
||||
|
||||
if (smooth_time)
|
||||
UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
|
||||
|
||||
/* Pre-compensate the transmit time by approximately how long it will take
|
||||
to generate the authentication data */
|
||||
if (auth)
|
||||
NAU_AdjustRequestTimestamp(auth, &local_transmit);
|
||||
else
|
||||
NAU_AdjustResponseTimestamp(request, request_info, &local_transmit);
|
||||
/* Get a more accurate transmit timestamp if it needs to be saved in the
|
||||
packet (i.e. in the server, symmetric, and broadcast basic modes) */
|
||||
if (!interleaved && precision < 32) {
|
||||
LCL_ReadCookedTime(&local_transmit, &local_transmit_err);
|
||||
if (smooth_time)
|
||||
UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
|
||||
}
|
||||
|
||||
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
|
||||
&message.transmit_ts, &ts_fuzz);
|
||||
@@ -1112,9 +1100,16 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the transmit timestamp will be saved, get an even more
|
||||
accurate daemon timestamp closer to the transmission */
|
||||
if (local_tx)
|
||||
LCL_ReadCookedTime(&local_transmit, &local_transmit_err);
|
||||
|
||||
ret = NIO_SendPacket(&message, where_to, from, info.length, local_tx != NULL);
|
||||
|
||||
if (local_tx) {
|
||||
if (smooth_time)
|
||||
UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
|
||||
local_tx->ts = local_transmit;
|
||||
local_tx->err = local_transmit_err;
|
||||
local_tx->source = NTP_TS_DAEMON;
|
||||
@@ -1796,8 +1791,8 @@ process_response(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Slowly increase the polling interval if we can't get good packet */
|
||||
adjust_poll(inst, 0.1);
|
||||
/* Slowly increase the polling interval if we can't get a good response */
|
||||
adjust_poll(inst, testD ? 0.02 : 0.1);
|
||||
}
|
||||
|
||||
/* If in client mode, no more packets are expected to be coming from the
|
||||
@@ -2081,10 +2076,10 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||
}
|
||||
|
||||
kod = 0;
|
||||
log_index = CLG_LogNTPAccess(&remote_addr->ip_addr, &rx_ts->ts);
|
||||
log_index = CLG_LogServiceAccess(CLG_NTP, &remote_addr->ip_addr, &rx_ts->ts);
|
||||
|
||||
/* Don't reply to all requests if the rate is excessive */
|
||||
if (log_index >= 0 && CLG_LimitNTPResponseRate(log_index)) {
|
||||
if (log_index >= 0 && CLG_LimitServiceRate(CLG_NTP, log_index)) {
|
||||
DEBUG_LOG("NTP packet discarded to limit response rate");
|
||||
return;
|
||||
}
|
||||
@@ -2096,10 +2091,12 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||
/* Don't respond unless a non-zero KoD was returned */
|
||||
if (kod == 0)
|
||||
return;
|
||||
} else if (info.auth.mode != NTP_AUTH_NONE && info.auth.mode != NTP_AUTH_MSSNTP) {
|
||||
CLG_LogAuthNtpRequest();
|
||||
}
|
||||
|
||||
/* If it is an NTPv4 packet with a long MAC and no extension fields,
|
||||
respond with a NTPv3 packet to avoid breaking RFC 7822 and keep
|
||||
respond with an NTPv3 packet to avoid breaking RFC 7822 and keep
|
||||
the length symmetric. Otherwise, respond with the same version. */
|
||||
if (info.version == 4 && info.ext_fields == 0 && info.auth.mode == NTP_AUTH_SYMMETRIC &&
|
||||
info.auth.mac.length > NTP_MAX_V4_MAC_LENGTH)
|
||||
@@ -2255,13 +2252,9 @@ NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double dof
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NCR_SetConnectivity(NCR_Instance inst, SRC_Connectivity connectivity)
|
||||
static void
|
||||
set_connectivity(NCR_Instance inst, SRC_Connectivity connectivity)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = UTI_IPToString(&inst->remote_addr.ip_addr);
|
||||
|
||||
if (connectivity == SRC_MAYBE_ONLINE)
|
||||
connectivity = NIO_IsServerConnectable(&inst->remote_addr) ? SRC_ONLINE : SRC_OFFLINE;
|
||||
|
||||
@@ -2272,17 +2265,17 @@ NCR_SetConnectivity(NCR_Instance inst, SRC_Connectivity connectivity)
|
||||
/* Nothing to do */
|
||||
break;
|
||||
case MD_OFFLINE:
|
||||
LOG(LOGS_INFO, "Source %s online", s);
|
||||
inst->opmode = MD_ONLINE;
|
||||
NCR_ResetInstance(inst);
|
||||
start_initial_timeout(inst);
|
||||
if (inst->auto_iburst)
|
||||
NCR_InitiateSampleBurst(inst, IBURST_GOOD_SAMPLES, IBURST_TOTAL_SAMPLES);
|
||||
break;
|
||||
case MD_BURST_WAS_ONLINE:
|
||||
/* Will revert */
|
||||
break;
|
||||
case MD_BURST_WAS_OFFLINE:
|
||||
inst->opmode = MD_BURST_WAS_ONLINE;
|
||||
LOG(LOGS_INFO, "Source %s online", s);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -2291,14 +2284,12 @@ NCR_SetConnectivity(NCR_Instance inst, SRC_Connectivity connectivity)
|
||||
case SRC_OFFLINE:
|
||||
switch (inst->opmode) {
|
||||
case MD_ONLINE:
|
||||
LOG(LOGS_INFO, "Source %s offline", s);
|
||||
take_offline(inst);
|
||||
break;
|
||||
case MD_OFFLINE:
|
||||
break;
|
||||
case MD_BURST_WAS_ONLINE:
|
||||
inst->opmode = MD_BURST_WAS_OFFLINE;
|
||||
LOG(LOGS_INFO, "Source %s offline", s);
|
||||
break;
|
||||
case MD_BURST_WAS_OFFLINE:
|
||||
break;
|
||||
@@ -2313,6 +2304,26 @@ NCR_SetConnectivity(NCR_Instance inst, SRC_Connectivity connectivity)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NCR_SetConnectivity(NCR_Instance inst, SRC_Connectivity connectivity)
|
||||
{
|
||||
OperatingMode prev_opmode;
|
||||
int was_online, is_online;
|
||||
|
||||
prev_opmode = inst->opmode;
|
||||
|
||||
set_connectivity(inst, connectivity);
|
||||
|
||||
/* Report an important change */
|
||||
was_online = prev_opmode == MD_ONLINE || prev_opmode == MD_BURST_WAS_ONLINE;
|
||||
is_online = inst->opmode == MD_ONLINE || inst->opmode == MD_BURST_WAS_ONLINE;
|
||||
if (was_online != is_online)
|
||||
LOG(LOGS_INFO, "Source %s %s",
|
||||
UTI_IPToString(&inst->remote_addr.ip_addr), is_online ? "online" : "offline");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
|
||||
{
|
||||
@@ -2444,6 +2455,14 @@ NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timespec *n
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NCR_GetAuthReport(NCR_Instance inst, RPT_AuthReport *report)
|
||||
{
|
||||
NAU_GetReport(inst->auth, report);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NCR_GetNTPReport(NCR_Instance inst, RPT_NTPReport *report)
|
||||
{
|
||||
@@ -2596,14 +2615,13 @@ broadcast_timeout(void *arg)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
|
||||
NCR_AddBroadcastDestination(NTP_Remote_Address *addr, int interval)
|
||||
{
|
||||
BroadcastDestination *destination;
|
||||
|
||||
destination = (BroadcastDestination *)ARR_GetNewElement(broadcasts);
|
||||
|
||||
destination->addr.ip_addr = *addr;
|
||||
destination->addr.port = port;
|
||||
destination->addr = *addr;
|
||||
destination->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
destination->local_addr.if_index = INVALID_IF_INDEX;
|
||||
destination->local_addr.sock_fd = NIO_OpenServerSocket(&destination->addr);
|
||||
|
||||
@@ -122,6 +122,7 @@ extern void NCR_ModifyPolltarget(NCR_Instance inst, int new_poll_target);
|
||||
extern void NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_samples);
|
||||
|
||||
extern void NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timespec *now);
|
||||
extern void NCR_GetAuthReport(NCR_Instance inst, RPT_AuthReport *report);
|
||||
extern void NCR_GetNTPReport(NCR_Instance inst, RPT_NTPReport *report);
|
||||
|
||||
extern int NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all);
|
||||
@@ -138,6 +139,6 @@ extern int NCR_IsSyncPeer(NCR_Instance instance);
|
||||
|
||||
extern void NCR_DumpAuthData(NCR_Instance inst);
|
||||
|
||||
extern void NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval);
|
||||
extern void NCR_AddBroadcastDestination(NTP_Remote_Address *addr, int interval);
|
||||
|
||||
#endif /* GOT_NTP_CORE_H */
|
||||
|
||||
60
ntp_io.c
60
ntp_io.c
@@ -83,19 +83,20 @@ static void read_from_socket(int sock_fd, int event, void *anything);
|
||||
static int
|
||||
open_socket(int family, int local_port, int client_only, IPSockAddr *remote_addr)
|
||||
{
|
||||
int sock_fd, sock_flags, events = SCH_FILE_INPUT;
|
||||
int sock_fd, sock_flags, dscp, events = SCH_FILE_INPUT;
|
||||
IPSockAddr local_addr;
|
||||
char *iface;
|
||||
|
||||
if (!SCK_IsFamilySupported(family))
|
||||
if (!SCK_IsIpFamilyEnabled(family))
|
||||
return INVALID_SOCK_FD;
|
||||
|
||||
if (!client_only)
|
||||
if (!client_only) {
|
||||
CNF_GetBindAddress(family, &local_addr.ip_addr);
|
||||
else
|
||||
iface = CNF_GetBindNtpInterface();
|
||||
} else {
|
||||
CNF_GetBindAcquisitionAddress(family, &local_addr.ip_addr);
|
||||
|
||||
if (local_addr.ip_addr.family != family)
|
||||
SCK_GetAnyLocalIPAddress(family, &local_addr.ip_addr);
|
||||
iface = CNF_GetBindAcquisitionInterface();
|
||||
}
|
||||
|
||||
local_addr.port = local_port;
|
||||
|
||||
@@ -103,13 +104,21 @@ open_socket(int family, int local_port, int client_only, IPSockAddr *remote_addr
|
||||
if (!client_only)
|
||||
sock_flags |= SCK_FLAG_BROADCAST;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(remote_addr, &local_addr, sock_flags);
|
||||
sock_fd = SCK_OpenUdpSocket(remote_addr, &local_addr, iface, sock_flags);
|
||||
if (sock_fd < 0) {
|
||||
if (!client_only)
|
||||
LOG(LOGS_ERR, "Could not open NTP socket on %s", UTI_IPSockAddrToString(&local_addr));
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
dscp = CNF_GetNtpDscp();
|
||||
if (dscp > 0 && dscp < 64) {
|
||||
#ifdef IP_TOS
|
||||
if (!SCK_SetIntOption(sock_fd, IPPROTO_IP, IP_TOS, dscp << 2))
|
||||
;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!client_only && family == IPADDR_INET4 && local_addr.port > 0)
|
||||
bound_server_sock_fd4 = local_addr.ip_addr.addr.in4 != INADDR_ANY;
|
||||
|
||||
@@ -152,7 +161,7 @@ close_socket(int sock_fd)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Initialise(int family)
|
||||
NIO_Initialise(void)
|
||||
{
|
||||
int server_port, client_port;
|
||||
|
||||
@@ -191,25 +200,18 @@ NIO_Initialise(int family)
|
||||
server_sock_ref4 = 0;
|
||||
server_sock_ref6 = 0;
|
||||
|
||||
if (family == IPADDR_UNSPEC || family == IPADDR_INET4) {
|
||||
if (permanent_server_sockets && server_port)
|
||||
server_sock_fd4 = open_socket(IPADDR_INET4, server_port, 0, NULL);
|
||||
if (!separate_client_sockets) {
|
||||
if (client_port != server_port || !server_port)
|
||||
client_sock_fd4 = open_socket(IPADDR_INET4, client_port, 1, NULL);
|
||||
else
|
||||
client_sock_fd4 = server_sock_fd4;
|
||||
}
|
||||
if (permanent_server_sockets && server_port) {
|
||||
server_sock_fd4 = open_socket(IPADDR_INET4, server_port, 0, NULL);
|
||||
server_sock_fd6 = open_socket(IPADDR_INET6, server_port, 0, NULL);
|
||||
}
|
||||
|
||||
if (family == IPADDR_UNSPEC || family == IPADDR_INET6) {
|
||||
if (permanent_server_sockets && server_port)
|
||||
server_sock_fd6 = open_socket(IPADDR_INET6, server_port, 0, NULL);
|
||||
if (!separate_client_sockets) {
|
||||
if (client_port != server_port || !server_port)
|
||||
client_sock_fd6 = open_socket(IPADDR_INET6, client_port, 1, NULL);
|
||||
else
|
||||
client_sock_fd6 = server_sock_fd6;
|
||||
if (!separate_client_sockets) {
|
||||
if (client_port != server_port || !server_port) {
|
||||
client_sock_fd4 = open_socket(IPADDR_INET4, client_port, 1, NULL);
|
||||
client_sock_fd6 = open_socket(IPADDR_INET6, client_port, 1, NULL);
|
||||
} else {
|
||||
client_sock_fd4 = server_sock_fd4;
|
||||
client_sock_fd6 = server_sock_fd6;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,9 +457,13 @@ NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
|
||||
message.remote_addr.ip.port = remote_addr->port;
|
||||
}
|
||||
|
||||
message.if_index = local_addr->if_index;
|
||||
message.local_addr.ip = local_addr->ip_addr;
|
||||
|
||||
/* Don't require responses to non-link-local addresses to use the same
|
||||
interface */
|
||||
message.if_index = SCK_IsLinkLocalIPAddress(&message.remote_addr.ip.ip_addr) ?
|
||||
local_addr->if_index : INVALID_IF_INDEX;
|
||||
|
||||
#if !defined(HAVE_IN_PKTINFO) && defined(IP_SENDSRCADDR)
|
||||
/* On FreeBSD a local IPv4 address cannot be specified on bound socket */
|
||||
if (message.local_addr.ip.family == IPADDR_INET4 &&
|
||||
|
||||
2
ntp_io.h
2
ntp_io.h
@@ -33,7 +33,7 @@
|
||||
#include "addressing.h"
|
||||
|
||||
/* Function to initialise the module. */
|
||||
extern void NIO_Initialise(int family);
|
||||
extern void NIO_Initialise(void);
|
||||
|
||||
/* Function to finalise the module */
|
||||
extern void NIO_Finalise(void);
|
||||
|
||||
@@ -125,7 +125,7 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
||||
return 1;
|
||||
}
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return 0;
|
||||
|
||||
@@ -285,7 +285,7 @@ update_interface_speed(struct Interface *iface)
|
||||
struct ifreq req;
|
||||
int sock_fd, link_speed;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return;
|
||||
|
||||
@@ -320,7 +320,7 @@ check_timestamping_option(int option)
|
||||
{
|
||||
int sock_fd;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return 0;
|
||||
|
||||
@@ -341,7 +341,7 @@ open_dummy_socket(void)
|
||||
{
|
||||
int sock_fd, events = 0;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, 0);
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return INVALID_SOCK_FD;
|
||||
|
||||
@@ -757,7 +757,7 @@ NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
|
||||
l2_length = message->length;
|
||||
message->length = extract_udp_data(message->data, &message->remote_addr.ip, message->length);
|
||||
|
||||
DEBUG_LOG("Extracted message for %s fd=%d len=%u",
|
||||
DEBUG_LOG("Extracted message for %s fd=%d len=%d",
|
||||
UTI_IPSockAddrToString(&message->remote_addr.ip),
|
||||
local_addr->sock_fd, message->length);
|
||||
|
||||
|
||||
20
ntp_signd.c
20
ntp_signd.c
@@ -96,14 +96,6 @@ static unsigned int queue_tail;
|
||||
/* Unix domain socket connected to ntp_signd */
|
||||
static int sock_fd;
|
||||
|
||||
#define MIN_AUTH_DELAY 1.0e-5
|
||||
#define MAX_AUTH_DELAY 1.0e-2
|
||||
|
||||
/* Average time needed for signing one packet. This is used to adjust the
|
||||
transmit timestamp in NTP packets. The timestamp won't be very accurate as
|
||||
the delay is variable, but it should be good enough for MS-SNTP clients. */
|
||||
static double auth_delay;
|
||||
|
||||
/* Flag indicating if the MS-SNTP authentication is enabled */
|
||||
static int enabled;
|
||||
|
||||
@@ -183,10 +175,6 @@ process_response(SignInstance *inst)
|
||||
NIO_SendPacket(&inst->response.signed_packet, &inst->remote_addr, &inst->local_addr,
|
||||
ntohl(inst->response.length) + sizeof (inst->response.length) -
|
||||
offsetof(SigndResponse, signed_packet), 0);
|
||||
|
||||
/* Update exponential moving average of the authentication delay */
|
||||
delay = CLAMP(MIN_AUTH_DELAY, delay, MAX_AUTH_DELAY);
|
||||
auth_delay += 0.1 * (delay - auth_delay);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -274,7 +262,6 @@ void
|
||||
NSD_Initialise()
|
||||
{
|
||||
sock_fd = INVALID_SOCK_FD;
|
||||
auth_delay = MIN_AUTH_DELAY;
|
||||
enabled = CNF_GetNtpSigndSocket() && CNF_GetNtpSigndSocket()[0];
|
||||
|
||||
if (!enabled)
|
||||
@@ -301,13 +288,6 @@ NSD_Finalise()
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
extern int NSD_GetAuthDelay(uint32_t key_id)
|
||||
{
|
||||
return 1.0e9 * auth_delay;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info,
|
||||
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
|
||||
|
||||
@@ -35,9 +35,6 @@ extern void NSD_Initialise(void);
|
||||
/* Finalisation function */
|
||||
extern void NSD_Finalise(void);
|
||||
|
||||
/* Function to get an estimate of delay due to signing */
|
||||
extern int NSD_GetAuthDelay(uint32_t key_id);
|
||||
|
||||
/* Function to sign an NTP packet and send it */
|
||||
extern int NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info,
|
||||
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr);
|
||||
|
||||
422
ntp_sources.c
422
ntp_sources.c
@@ -54,10 +54,12 @@ typedef struct {
|
||||
is not resolved yet) */
|
||||
NCR_Instance data; /* Data for the protocol engine for this source */
|
||||
char *name; /* Name of the source, may be NULL */
|
||||
int pool; /* Number of the pool from which was this source
|
||||
int pool_id; /* ID of the pool from which was this source
|
||||
added or INVALID_POOL */
|
||||
int tentative; /* Flag indicating there was no valid response
|
||||
received from the source yet */
|
||||
uint32_t conf_id; /* Configuration ID, which can be shared with
|
||||
different sources in case of a pool */
|
||||
} SourceRecord;
|
||||
|
||||
/* Hash table of SourceRecord, its size is a power of two and it's never
|
||||
@@ -73,13 +75,16 @@ static int auto_start_sources = 0;
|
||||
/* Last assigned address ID */
|
||||
static uint32_t last_address_id = 0;
|
||||
|
||||
/* Last assigned configuration ID */
|
||||
static uint32_t last_conf_id = 0;
|
||||
|
||||
/* Source scheduled for name resolving (first resolving or replacement) */
|
||||
struct UnresolvedSource {
|
||||
/* Current address of the source (IDADDR_ID is used for a single source
|
||||
with unknown address and IPADDR_UNSPEC for a pool of sources */
|
||||
/* Current address of the source (IPADDR_ID is used for a single source
|
||||
with unknown address and IPADDR_UNSPEC for a pool of sources) */
|
||||
NTP_Remote_Address address;
|
||||
/* ID of the pool if not a single source */
|
||||
int pool;
|
||||
int pool_id;
|
||||
/* Name to be resolved */
|
||||
char *name;
|
||||
/* Flag indicating addresses should be used in a random order */
|
||||
@@ -114,7 +119,7 @@ struct SourcePool {
|
||||
int max_sources;
|
||||
};
|
||||
|
||||
/* Array of SourcePool */
|
||||
/* Array of SourcePool (indexed by their ID) */
|
||||
static ARR_Instance pools;
|
||||
|
||||
/* ================================================== */
|
||||
@@ -123,7 +128,7 @@ static ARR_Instance pools;
|
||||
static void resolve_sources(void);
|
||||
static void rehash_records(void);
|
||||
static void clean_source_record(SourceRecord *record);
|
||||
static void remove_pool_sources(int pool, int tentative, int unresolved);
|
||||
static void remove_pool_sources(int pool_id, int tentative, int unresolved);
|
||||
static void remove_unresolved_source(struct UnresolvedSource *us);
|
||||
|
||||
static void
|
||||
@@ -185,6 +190,8 @@ NSR_Finalise(void)
|
||||
clean_source_record(record);
|
||||
}
|
||||
|
||||
LCL_RemoveParameterChangeHandler(slew_sources, NULL);
|
||||
|
||||
ARR_DestroyInstance(records);
|
||||
ARR_DestroyInstance(pools);
|
||||
|
||||
@@ -195,39 +202,30 @@ NSR_Finalise(void)
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return slot number and whether the IP address was matched or not.
|
||||
found = 0 => Neither IP nor port matched, empty slot returned
|
||||
found = 1 => Only IP matched, port doesn't match
|
||||
found = 2 => Both IP and port matched.
|
||||
/* Find a slot matching an IP address. It is assumed that there can
|
||||
only ever be one record for a particular IP address. */
|
||||
|
||||
It is assumed that there can only ever be one record for a
|
||||
particular IP address. (If a different port comes up, it probably
|
||||
means someone is running ntpdate -d or something). Thus, if we
|
||||
match the IP address we stop the search regardless of whether the
|
||||
port number matches.
|
||||
|
||||
*/
|
||||
|
||||
static void
|
||||
find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
|
||||
static int
|
||||
find_slot(IPAddr *ip_addr, int *slot)
|
||||
{
|
||||
SourceRecord *record;
|
||||
uint32_t hash;
|
||||
unsigned int i, size;
|
||||
unsigned short port;
|
||||
|
||||
size = ARR_GetSize(records);
|
||||
|
||||
*slot = 0;
|
||||
*found = 0;
|
||||
|
||||
if (remote_addr->ip_addr.family != IPADDR_INET4 &&
|
||||
remote_addr->ip_addr.family != IPADDR_INET6 &&
|
||||
remote_addr->ip_addr.family != IPADDR_ID)
|
||||
return;
|
||||
switch (ip_addr->family) {
|
||||
case IPADDR_INET4:
|
||||
case IPADDR_INET6:
|
||||
case IPADDR_ID:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
hash = UTI_IPToHash(&remote_addr->ip_addr);
|
||||
port = remote_addr->port;
|
||||
hash = UTI_IPToHash(ip_addr);
|
||||
|
||||
for (i = 0; i < size / 2; i++) {
|
||||
/* Use quadratic probing */
|
||||
@@ -237,12 +235,26 @@ find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
|
||||
if (!record->remote_addr)
|
||||
break;
|
||||
|
||||
if (!UTI_CompareIPs(&record->remote_addr->ip_addr,
|
||||
&remote_addr->ip_addr, NULL)) {
|
||||
*found = record->remote_addr->port == port ? 2 : 1;
|
||||
return;
|
||||
}
|
||||
if (UTI_CompareIPs(&record->remote_addr->ip_addr, ip_addr, NULL) == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Find a slot matching an IP address and port. The function returns:
|
||||
0 => IP not matched, empty slot returned if a valid address was provided
|
||||
1 => Only IP matched, port doesn't match
|
||||
2 => Both IP and port matched. */
|
||||
|
||||
static int
|
||||
find_slot2(NTP_Remote_Address *remote_addr, int *slot)
|
||||
{
|
||||
if (!find_slot(&remote_addr->ip_addr, slot))
|
||||
return 0;
|
||||
|
||||
return get_record(*slot)->remote_addr->port == remote_addr->port ? 2 : 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -261,7 +273,7 @@ rehash_records(void)
|
||||
{
|
||||
SourceRecord *temp_records;
|
||||
unsigned int i, old_size, new_size;
|
||||
int slot, found;
|
||||
int slot;
|
||||
|
||||
old_size = ARR_GetSize(records);
|
||||
|
||||
@@ -281,8 +293,8 @@ rehash_records(void)
|
||||
if (!temp_records[i].remote_addr)
|
||||
continue;
|
||||
|
||||
find_slot(temp_records[i].remote_addr, &slot, &found);
|
||||
assert(!found);
|
||||
if (find_slot2(temp_records[i].remote_addr, &slot) != 0)
|
||||
assert(0);
|
||||
|
||||
*get_record(slot) = temp_records[i];
|
||||
}
|
||||
@@ -294,16 +306,16 @@ rehash_records(void)
|
||||
|
||||
/* Procedure to add a new source */
|
||||
static NSR_Status
|
||||
add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, SourceParameters *params, int pool)
|
||||
add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type,
|
||||
SourceParameters *params, int pool_id, uint32_t conf_id)
|
||||
{
|
||||
SourceRecord *record;
|
||||
int slot, found;
|
||||
int slot;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
/* Find empty bin & check that we don't have the address already */
|
||||
find_slot(remote_addr, &slot, &found);
|
||||
if (found) {
|
||||
if (find_slot2(remote_addr, &slot) != 0) {
|
||||
return NSR_AlreadyInUse;
|
||||
} else {
|
||||
if (remote_addr->ip_addr.family != IPADDR_INET4 &&
|
||||
@@ -315,21 +327,22 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, So
|
||||
|
||||
if (!check_hashtable_size(n_sources, ARR_GetSize(records))) {
|
||||
rehash_records();
|
||||
find_slot(remote_addr, &slot, &found);
|
||||
if (find_slot2(remote_addr, &slot) != 0)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
assert(!found);
|
||||
record = get_record(slot);
|
||||
record->data = NCR_CreateInstance(remote_addr, type, params, name);
|
||||
record->remote_addr = NCR_GetRemoteAddress(record->data);
|
||||
record->name = name ? Strdup(name) : NULL;
|
||||
record->pool = pool;
|
||||
record->pool_id = pool_id;
|
||||
record->tentative = 1;
|
||||
record->conf_id = conf_id;
|
||||
|
||||
if (record->pool != INVALID_POOL) {
|
||||
get_pool(record->pool)->sources++;
|
||||
if (record->pool_id != INVALID_POOL) {
|
||||
get_pool(record->pool_id)->sources++;
|
||||
if (!UTI_IsIPReal(&remote_addr->ip_addr))
|
||||
get_pool(record->pool)->unresolved_sources++;
|
||||
get_pool(record->pool_id)->unresolved_sources++;
|
||||
}
|
||||
|
||||
if (auto_start_sources && UTI_IsIPReal(&remote_addr->ip_addr))
|
||||
@@ -351,13 +364,13 @@ change_source_address(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr
|
||||
LOG_Severity severity;
|
||||
char *name;
|
||||
|
||||
find_slot(old_addr, &slot1, &found);
|
||||
if (!found)
|
||||
found = find_slot2(old_addr, &slot1);
|
||||
if (found == 0)
|
||||
return NSR_NoSuchSource;
|
||||
|
||||
/* Make sure there is no other source using the new address (with the same
|
||||
or different port), but allow a source to have its port changed */
|
||||
find_slot(new_addr, &slot2, &found);
|
||||
found = find_slot2(new_addr, &slot2);
|
||||
if (found == 2 || (found != 0 && slot1 != slot2))
|
||||
return NSR_AlreadyInUse;
|
||||
|
||||
@@ -367,15 +380,15 @@ change_source_address(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr
|
||||
if (!UTI_IsIPReal(&old_addr->ip_addr) && UTI_IsIPReal(&new_addr->ip_addr)) {
|
||||
if (auto_start_sources)
|
||||
NCR_StartInstance(record->data);
|
||||
if (record->pool != INVALID_POOL)
|
||||
get_pool(record->pool)->unresolved_sources--;
|
||||
if (record->pool_id != INVALID_POOL)
|
||||
get_pool(record->pool_id)->unresolved_sources--;
|
||||
}
|
||||
|
||||
if (!record->tentative) {
|
||||
record->tentative = 1;
|
||||
|
||||
if (record->pool != INVALID_POOL)
|
||||
get_pool(record->pool)->confirmed_sources--;
|
||||
if (record->pool_id != INVALID_POOL)
|
||||
get_pool(record->pool_id)->confirmed_sources--;
|
||||
}
|
||||
|
||||
name = record->name;
|
||||
@@ -430,12 +443,12 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
|
||||
|
||||
DEBUG_LOG("(%d) %s", i + 1, UTI_IPToString(&new_addr.ip_addr));
|
||||
|
||||
if (us->pool != INVALID_POOL) {
|
||||
if (us->pool_id != INVALID_POOL) {
|
||||
/* In the pool resolving mode, try to replace all sources from
|
||||
the pool which don't have a real address yet */
|
||||
for (j = 0; j < ARR_GetSize(records); j++) {
|
||||
record = get_record(j);
|
||||
if (!record->remote_addr || record->pool != us->pool ||
|
||||
if (!record->remote_addr || record->pool_id != us->pool_id ||
|
||||
UTI_IsIPReal(&record->remote_addr->ip_addr))
|
||||
continue;
|
||||
old_addr = *record->remote_addr;
|
||||
@@ -456,15 +469,14 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
|
||||
static int
|
||||
is_resolved(struct UnresolvedSource *us)
|
||||
{
|
||||
int slot, found;
|
||||
int slot;
|
||||
|
||||
if (us->pool != INVALID_POOL) {
|
||||
return get_pool(us->pool)->unresolved_sources <= 0;
|
||||
if (us->pool_id != INVALID_POOL) {
|
||||
return get_pool(us->pool_id)->unresolved_sources <= 0;
|
||||
} else {
|
||||
/* If the address is no longer present, it was removed or replaced
|
||||
(i.e. resolved) */
|
||||
find_slot(&us->address, &slot, &found);
|
||||
return !found;
|
||||
return find_slot2(&us->address, &slot) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,27 +609,64 @@ remove_unresolved_source(struct UnresolvedSource *us)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
NSR_Status
|
||||
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
|
||||
static int get_unused_pool_id(void)
|
||||
{
|
||||
return add_source(remote_addr, NULL, type, params, INVALID_POOL);
|
||||
struct UnresolvedSource *us;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(pools); i++) {
|
||||
if (get_pool(i)->sources > 0)
|
||||
continue;
|
||||
|
||||
/* Make sure there is no name waiting to be resolved using this pool */
|
||||
for (us = unresolved_sources; us; us = us->next) {
|
||||
if (us->pool_id == i)
|
||||
break;
|
||||
}
|
||||
if (us)
|
||||
continue;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
return INVALID_POOL;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
NSR_Status
|
||||
NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params)
|
||||
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
|
||||
SourceParameters *params, uint32_t *conf_id)
|
||||
{
|
||||
NSR_Status s;
|
||||
|
||||
s = add_source(remote_addr, NULL, type, params, INVALID_POOL, last_conf_id + 1);
|
||||
if (s != NSR_Success)
|
||||
return s;
|
||||
|
||||
last_conf_id++;
|
||||
if (conf_id)
|
||||
*conf_id = last_conf_id;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
NSR_Status
|
||||
NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
|
||||
SourceParameters *params, uint32_t *conf_id)
|
||||
{
|
||||
struct UnresolvedSource *us;
|
||||
struct SourcePool *sp;
|
||||
NTP_Remote_Address remote_addr;
|
||||
int i, new_sources;
|
||||
int i, new_sources, pool_id;
|
||||
|
||||
/* If the name is an IP address, don't bother with full resolving now
|
||||
or later when trying to replace the source */
|
||||
if (UTI_StringToIP(name, &remote_addr.ip_addr)) {
|
||||
remote_addr.port = port;
|
||||
return NSR_AddSource(&remote_addr, type, params);
|
||||
return NSR_AddSource(&remote_addr, type, params, conf_id);
|
||||
}
|
||||
|
||||
/* Make sure the name is at least printable and has no spaces */
|
||||
@@ -635,26 +684,37 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source
|
||||
remote_addr.port = port;
|
||||
|
||||
if (!pool) {
|
||||
us->pool = INVALID_POOL;
|
||||
us->pool_id = INVALID_POOL;
|
||||
us->address = remote_addr;
|
||||
new_sources = 1;
|
||||
} else {
|
||||
sp = (struct SourcePool *)ARR_GetNewElement(pools);
|
||||
pool_id = get_unused_pool_id();
|
||||
if (pool_id != INVALID_POOL) {
|
||||
sp = get_pool(pool_id);
|
||||
} else {
|
||||
sp = ARR_GetNewElement(pools);
|
||||
pool_id = ARR_GetSize(pools) - 1;
|
||||
}
|
||||
|
||||
sp->sources = 0;
|
||||
sp->unresolved_sources = 0;
|
||||
sp->confirmed_sources = 0;
|
||||
sp->max_sources = CLAMP(1, params->max_sources, MAX_POOL_SOURCES);
|
||||
us->pool = ARR_GetSize(pools) - 1;
|
||||
us->pool_id = pool_id;
|
||||
us->address.ip_addr.family = IPADDR_UNSPEC;
|
||||
new_sources = MIN(2 * sp->max_sources, MAX_POOL_SOURCES);
|
||||
}
|
||||
|
||||
append_unresolved_source(us);
|
||||
|
||||
last_conf_id++;
|
||||
if (conf_id)
|
||||
*conf_id = last_conf_id;
|
||||
|
||||
for (i = 0; i < new_sources; i++) {
|
||||
if (i > 0)
|
||||
remote_addr.ip_addr.addr.id = ++last_address_id;
|
||||
if (add_source(&remote_addr, name, type, params, us->pool) != NSR_Success)
|
||||
if (add_source(&remote_addr, name, type, params, us->pool_id, last_conf_id) != NSR_Success)
|
||||
return NSR_TooManySources;
|
||||
}
|
||||
|
||||
@@ -721,8 +781,8 @@ clean_source_record(SourceRecord *record)
|
||||
{
|
||||
assert(record->remote_addr);
|
||||
|
||||
if (record->pool != INVALID_POOL) {
|
||||
struct SourcePool *pool = get_pool(record->pool);
|
||||
if (record->pool_id != INVALID_POOL) {
|
||||
struct SourcePool *pool = get_pool(record->pool_id);
|
||||
|
||||
pool->sources--;
|
||||
if (!UTI_IsIPReal(&record->remote_addr->ip_addr))
|
||||
@@ -745,19 +805,16 @@ clean_source_record(SourceRecord *record)
|
||||
|
||||
/* Procedure to remove a source. We don't bother whether the port
|
||||
address is matched - we're only interested in removing a record for
|
||||
the right IP address. Thus the caller can specify the port number
|
||||
as zero if it wishes. */
|
||||
the right IP address. */
|
||||
NSR_Status
|
||||
NSR_RemoveSource(NTP_Remote_Address *remote_addr)
|
||||
NSR_RemoveSource(IPAddr *address)
|
||||
{
|
||||
int slot, found;
|
||||
int slot;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
find_slot(remote_addr, &slot, &found);
|
||||
if (!found) {
|
||||
if (find_slot(address, &slot) == 0)
|
||||
return NSR_NoSuchSource;
|
||||
}
|
||||
|
||||
clean_source_record(get_record(slot));
|
||||
|
||||
@@ -771,6 +828,24 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NSR_RemoveSourcesById(uint32_t conf_id)
|
||||
{
|
||||
SourceRecord *record;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(records); i++) {
|
||||
record = get_record(i);
|
||||
if (!record->remote_addr || record->conf_id != conf_id)
|
||||
continue;
|
||||
clean_source_record(record);
|
||||
}
|
||||
|
||||
rehash_records();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NSR_RemoveAllSources(void)
|
||||
{
|
||||
@@ -803,7 +878,7 @@ resolve_source_replacement(SourceRecord *record)
|
||||
stuck to a pair of addresses if the order doesn't change, or a group of
|
||||
IPv4/IPv6 addresses if the resolver prefers inaccessible IP family */
|
||||
us->random_order = record->tentative;
|
||||
us->pool = INVALID_POOL;
|
||||
us->pool_id = INVALID_POOL;
|
||||
us->address = *record->remote_addr;
|
||||
|
||||
append_unresolved_source(us);
|
||||
@@ -817,16 +892,11 @@ NSR_HandleBadSource(IPAddr *address)
|
||||
{
|
||||
static struct timespec last_replacement;
|
||||
struct timespec now;
|
||||
NTP_Remote_Address remote_addr;
|
||||
SourceRecord *record;
|
||||
int slot, found;
|
||||
double diff;
|
||||
int slot;
|
||||
|
||||
remote_addr.ip_addr = *address;
|
||||
remote_addr.port = 0;
|
||||
|
||||
find_slot(&remote_addr, &slot, &found);
|
||||
if (!found)
|
||||
if (!find_slot(address, &slot))
|
||||
return;
|
||||
|
||||
record = get_record(slot);
|
||||
@@ -877,7 +947,7 @@ NSR_UpdateSourceNtpAddress(NTP_Remote_Address *old_addr, NTP_Remote_Address *new
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void remove_pool_sources(int pool, int tentative, int unresolved)
|
||||
static void remove_pool_sources(int pool_id, int tentative, int unresolved)
|
||||
{
|
||||
SourceRecord *record;
|
||||
unsigned int i, removed;
|
||||
@@ -885,7 +955,7 @@ static void remove_pool_sources(int pool, int tentative, int unresolved)
|
||||
for (i = removed = 0; i < ARR_GetSize(records); i++) {
|
||||
record = get_record(i);
|
||||
|
||||
if (!record->remote_addr || record->pool != pool)
|
||||
if (!record->remote_addr || record->pool_id != pool_id)
|
||||
continue;
|
||||
|
||||
if ((tentative && !record->tentative) ||
|
||||
@@ -908,14 +978,9 @@ static void remove_pool_sources(int pool, int tentative, int unresolved)
|
||||
uint32_t
|
||||
NSR_GetLocalRefid(IPAddr *address)
|
||||
{
|
||||
NTP_Remote_Address remote_addr;
|
||||
int slot, found;
|
||||
int slot;
|
||||
|
||||
remote_addr.ip_addr = *address;
|
||||
remote_addr.port = 0;
|
||||
|
||||
find_slot(&remote_addr, &slot, &found);
|
||||
if (!found)
|
||||
if (!find_slot(address, &slot))
|
||||
return 0;
|
||||
|
||||
return NCR_GetLocalRefid(get_record(slot)->data);
|
||||
@@ -926,16 +991,11 @@ NSR_GetLocalRefid(IPAddr *address)
|
||||
char *
|
||||
NSR_GetName(IPAddr *address)
|
||||
{
|
||||
NTP_Remote_Address remote_addr;
|
||||
int slot, found;
|
||||
SourceRecord *record;
|
||||
int slot;
|
||||
|
||||
remote_addr.ip_addr = *address;
|
||||
remote_addr.port = 0;
|
||||
|
||||
find_slot(&remote_addr, &slot, &found);
|
||||
if (!found)
|
||||
return NULL;
|
||||
if (!find_slot(address, &slot))
|
||||
return 0;
|
||||
|
||||
record = get_record(slot);
|
||||
if (record->name)
|
||||
@@ -954,12 +1014,12 @@ NSR_ProcessRx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
{
|
||||
SourceRecord *record;
|
||||
struct SourcePool *pool;
|
||||
int slot, found;
|
||||
int slot;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
find_slot(remote_addr, &slot, &found);
|
||||
if (found == 2) { /* Must match IP address AND port number */
|
||||
/* Must match IP address AND port number */
|
||||
if (find_slot2(remote_addr, &slot) == 2) {
|
||||
record = get_record(slot);
|
||||
|
||||
if (!NCR_ProcessRxKnown(record->data, local_addr, rx_ts, message, length))
|
||||
@@ -969,8 +1029,8 @@ NSR_ProcessRx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
/* This was the first good reply from the source */
|
||||
record->tentative = 0;
|
||||
|
||||
if (record->pool != INVALID_POOL) {
|
||||
pool = get_pool(record->pool);
|
||||
if (record->pool_id != INVALID_POOL) {
|
||||
pool = get_pool(record->pool_id);
|
||||
pool->confirmed_sources++;
|
||||
|
||||
DEBUG_LOG("pool %s has %d confirmed sources", record->name, pool->confirmed_sources);
|
||||
@@ -978,7 +1038,7 @@ NSR_ProcessRx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
/* If the number of sources from the pool reached the configured
|
||||
maximum, remove the remaining tentative sources */
|
||||
if (pool->confirmed_sources >= pool->max_sources)
|
||||
remove_pool_sources(record->pool, 1, 0);
|
||||
remove_pool_sources(record->pool_id, 1, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -993,11 +1053,10 @@ NSR_ProcessTx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length)
|
||||
{
|
||||
SourceRecord *record;
|
||||
int slot, found;
|
||||
int slot;
|
||||
|
||||
find_slot(remote_addr, &slot, &found);
|
||||
|
||||
if (found == 2) { /* Must match IP address AND port number */
|
||||
/* Must match IP address AND port number */
|
||||
if (find_slot2(remote_addr, &slot) == 2) {
|
||||
record = get_record(slot);
|
||||
NCR_ProcessTxKnown(record->data, local_addr, tx_ts, message, length);
|
||||
} else {
|
||||
@@ -1074,18 +1133,13 @@ NSR_SetConnectivity(IPAddr *mask, IPAddr *address, SRC_Connectivity connectivity
|
||||
int
|
||||
NSR_ModifyMinpoll(IPAddr *address, int new_minpoll)
|
||||
{
|
||||
int slot, found;
|
||||
NTP_Remote_Address addr;
|
||||
addr.ip_addr = *address;
|
||||
addr.port = 0;
|
||||
int slot;
|
||||
|
||||
find_slot(&addr, &slot, &found);
|
||||
if (found == 0) {
|
||||
if (!find_slot(address, &slot))
|
||||
return 0;
|
||||
} else {
|
||||
NCR_ModifyMinpoll(get_record(slot)->data, new_minpoll);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NCR_ModifyMinpoll(get_record(slot)->data, new_minpoll);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1093,18 +1147,13 @@ NSR_ModifyMinpoll(IPAddr *address, int new_minpoll)
|
||||
int
|
||||
NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll)
|
||||
{
|
||||
int slot, found;
|
||||
NTP_Remote_Address addr;
|
||||
addr.ip_addr = *address;
|
||||
addr.port = 0;
|
||||
int slot;
|
||||
|
||||
find_slot(&addr, &slot, &found);
|
||||
if (found == 0) {
|
||||
if (!find_slot(address, &slot))
|
||||
return 0;
|
||||
} else {
|
||||
NCR_ModifyMaxpoll(get_record(slot)->data, new_maxpoll);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NCR_ModifyMaxpoll(get_record(slot)->data, new_maxpoll);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1112,18 +1161,13 @@ NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll)
|
||||
int
|
||||
NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay)
|
||||
{
|
||||
int slot, found;
|
||||
NTP_Remote_Address addr;
|
||||
addr.ip_addr = *address;
|
||||
addr.port = 0;
|
||||
int slot;
|
||||
|
||||
find_slot(&addr, &slot, &found);
|
||||
if (found == 0) {
|
||||
if (!find_slot(address, &slot))
|
||||
return 0;
|
||||
} else {
|
||||
NCR_ModifyMaxdelay(get_record(slot)->data, new_max_delay);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NCR_ModifyMaxdelay(get_record(slot)->data, new_max_delay);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1131,18 +1175,13 @@ NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay)
|
||||
int
|
||||
NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio)
|
||||
{
|
||||
int slot, found;
|
||||
NTP_Remote_Address addr;
|
||||
addr.ip_addr = *address;
|
||||
addr.port = 0;
|
||||
int slot;
|
||||
|
||||
find_slot(&addr, &slot, &found);
|
||||
if (found == 0) {
|
||||
if (!find_slot(address, &slot))
|
||||
return 0;
|
||||
} else {
|
||||
NCR_ModifyMaxdelayratio(get_record(slot)->data, new_max_delay_ratio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NCR_ModifyMaxdelayratio(get_record(slot)->data, new_max_delay_ratio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1150,18 +1189,13 @@ NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio)
|
||||
int
|
||||
NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio)
|
||||
{
|
||||
int slot, found;
|
||||
NTP_Remote_Address addr;
|
||||
addr.ip_addr = *address;
|
||||
addr.port = 0;
|
||||
int slot;
|
||||
|
||||
find_slot(&addr, &slot, &found);
|
||||
if (found == 0) {
|
||||
if (!find_slot(address, &slot))
|
||||
return 0;
|
||||
} else {
|
||||
NCR_ModifyMaxdelaydevratio(get_record(slot)->data, new_max_delay_dev_ratio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NCR_ModifyMaxdelaydevratio(get_record(slot)->data, new_max_delay_dev_ratio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1169,18 +1203,13 @@ NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio)
|
||||
int
|
||||
NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum)
|
||||
{
|
||||
int slot, found;
|
||||
NTP_Remote_Address addr;
|
||||
addr.ip_addr = *address;
|
||||
addr.port = 0;
|
||||
int slot;
|
||||
|
||||
find_slot(&addr, &slot, &found);
|
||||
if (found == 0) {
|
||||
if (!find_slot(address, &slot))
|
||||
return 0;
|
||||
} else {
|
||||
NCR_ModifyMinstratum(get_record(slot)->data, new_min_stratum);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NCR_ModifyMinstratum(get_record(slot)->data, new_min_stratum);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1188,18 +1217,13 @@ NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum)
|
||||
int
|
||||
NSR_ModifyPolltarget(IPAddr *address, int new_poll_target)
|
||||
{
|
||||
int slot, found;
|
||||
NTP_Remote_Address addr;
|
||||
addr.ip_addr = *address;
|
||||
addr.port = 0;
|
||||
int slot;
|
||||
|
||||
find_slot(&addr, &slot, &found);
|
||||
if (found == 0) {
|
||||
if (!find_slot(address, &slot))
|
||||
return 0;
|
||||
} else {
|
||||
NCR_ModifyPolltarget(get_record(slot)->data, new_poll_target);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NCR_ModifyPolltarget(get_record(slot)->data, new_poll_target);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1235,13 +1259,9 @@ NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples,
|
||||
void
|
||||
NSR_ReportSource(RPT_SourceReport *report, struct timespec *now)
|
||||
{
|
||||
NTP_Remote_Address rem_addr;
|
||||
int slot, found;
|
||||
int slot;
|
||||
|
||||
rem_addr.ip_addr = report->ip_addr;
|
||||
rem_addr.port = 0;
|
||||
find_slot(&rem_addr, &slot, &found);
|
||||
if (found) {
|
||||
if (find_slot(&report->ip_addr, &slot)) {
|
||||
NCR_ReportSource(get_record(slot)->data, report, now);
|
||||
} else {
|
||||
report->poll = 0;
|
||||
@@ -1249,6 +1269,20 @@ NSR_ReportSource(RPT_SourceReport *report, struct timespec *now)
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NSR_GetAuthReport(IPAddr *address, RPT_AuthReport *report)
|
||||
{
|
||||
int slot;
|
||||
|
||||
if (!find_slot(address, &slot))
|
||||
return 0;
|
||||
|
||||
NCR_GetAuthReport(get_record(slot)->data, report);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* The ip address is assumed to be completed on input, that is how we
|
||||
identify the source record. */
|
||||
@@ -1256,13 +1290,9 @@ NSR_ReportSource(RPT_SourceReport *report, struct timespec *now)
|
||||
int
|
||||
NSR_GetNTPReport(RPT_NTPReport *report)
|
||||
{
|
||||
NTP_Remote_Address rem_addr;
|
||||
int slot, found;
|
||||
int slot;
|
||||
|
||||
rem_addr.ip_addr = report->remote_addr;
|
||||
rem_addr.port = 0;
|
||||
find_slot(&rem_addr, &slot, &found);
|
||||
if (!found)
|
||||
if (!find_slot(&report->remote_addr, &slot))
|
||||
return 0;
|
||||
|
||||
NCR_GetNTPReport(get_record(slot)->data, report);
|
||||
|
||||
@@ -50,14 +50,15 @@ typedef enum {
|
||||
} NSR_Status;
|
||||
|
||||
/* Procedure to add a new server or peer source. */
|
||||
extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
|
||||
extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
|
||||
SourceParameters *params, uint32_t *conf_id);
|
||||
|
||||
/* Procedure to add a new server, peer source, or pool of servers specified by
|
||||
name instead of address. The name is resolved in exponentially increasing
|
||||
intervals until it succeeds or fails with a non-temporary error. If the
|
||||
name is an address, it is equivalent to NSR_AddSource(). */
|
||||
extern NSR_Status NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
|
||||
SourceParameters *params);
|
||||
SourceParameters *params, uint32_t *conf_id);
|
||||
|
||||
/* Function type for handlers to be called back when an attempt
|
||||
* (possibly unsuccessful) to resolve unresolved sources ends */
|
||||
@@ -76,7 +77,10 @@ extern void NSR_StartSources(void);
|
||||
extern void NSR_AutoStartSources(void);
|
||||
|
||||
/* Procedure to remove a source */
|
||||
extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
|
||||
extern NSR_Status NSR_RemoveSource(IPAddr *address);
|
||||
|
||||
/* Procedure to remove all sources matching a configuration ID */
|
||||
extern void NSR_RemoveSourcesById(uint32_t conf_id);
|
||||
|
||||
/* Procedure to remove all sources */
|
||||
extern void NSR_RemoveAllSources(void);
|
||||
@@ -136,6 +140,8 @@ extern int NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, IPAd
|
||||
|
||||
extern void NSR_ReportSource(RPT_SourceReport *report, struct timespec *now);
|
||||
|
||||
extern int NSR_GetAuthReport(IPAddr *address, RPT_AuthReport *report);
|
||||
|
||||
extern int NSR_GetNTPReport(RPT_NTPReport *report);
|
||||
|
||||
extern void NSR_GetActivityReport(RPT_ActivityReport *report);
|
||||
|
||||
2
nts_ke.h
2
nts_ke.h
@@ -29,6 +29,8 @@
|
||||
|
||||
#include "siv.h"
|
||||
|
||||
#define NKE_PORT 4460
|
||||
|
||||
#define NKE_RECORD_CRITICAL_BIT (1U << 15)
|
||||
#define NKE_RECORD_END_OF_MESSAGE 0
|
||||
#define NKE_RECORD_NEXT_PROTOCOL 1
|
||||
|
||||
@@ -58,7 +58,8 @@ struct NKC_Instance_Record {
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void *client_credentials;
|
||||
static void *client_credentials = NULL;
|
||||
static int client_credentials_refs = 0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -71,7 +72,7 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *arg
|
||||
inst->resolving_name = 0;
|
||||
|
||||
if (inst->destroying) {
|
||||
NKC_DestroyInstance(inst);
|
||||
Free(inst);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -84,7 +85,7 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *arg
|
||||
|
||||
inst->ntp_address.ip_addr = ip_addrs[0];
|
||||
|
||||
/* Prefer an address of the same family as NTS-KE */
|
||||
/* Prefer an address in the same family as the NTS-KE server */
|
||||
for (i = 0; i < n_addrs; i++) {
|
||||
DEBUG_LOG("%s resolved to %s", inst->server_name, UTI_IPToString(&ip_addrs[i]));
|
||||
if (ip_addrs[i].family == inst->address.ip_addr.family) {
|
||||
@@ -168,13 +169,21 @@ process_response(NKC_Instance inst)
|
||||
error = 1;
|
||||
break;
|
||||
case NKE_RECORD_COOKIE:
|
||||
DEBUG_LOG("Got cookie #%d length=%d", inst->num_cookies + 1, length);
|
||||
assert(NKE_MAX_COOKIE_LENGTH == sizeof (inst->cookies[inst->num_cookies].cookie));
|
||||
if (length <= NKE_MAX_COOKIE_LENGTH && inst->num_cookies < NKE_MAX_COOKIES) {
|
||||
inst->cookies[inst->num_cookies].length = length;
|
||||
memcpy(inst->cookies[inst->num_cookies].cookie, data, length);
|
||||
inst->num_cookies++;
|
||||
DEBUG_LOG("Got cookie length=%d", length);
|
||||
|
||||
if (length < 1 || length > NKE_MAX_COOKIE_LENGTH || length % 4 != 0 ||
|
||||
inst->num_cookies >= NKE_MAX_COOKIES) {
|
||||
DEBUG_LOG("Unexpected length/cookie");
|
||||
break;
|
||||
}
|
||||
|
||||
assert(NKE_MAX_COOKIE_LENGTH == sizeof (inst->cookies[inst->num_cookies].cookie));
|
||||
assert(NKE_MAX_COOKIES == sizeof (inst->cookies) /
|
||||
sizeof (inst->cookies[inst->num_cookies]));
|
||||
inst->cookies[inst->num_cookies].length = length;
|
||||
memcpy(inst->cookies[inst->num_cookies].cookie, data, length);
|
||||
|
||||
inst->num_cookies++;
|
||||
break;
|
||||
case NKE_RECORD_NTPV4_SERVER_NEGOTIATION:
|
||||
if (length < 1 || length >= sizeof (inst->server_name)) {
|
||||
@@ -256,23 +265,6 @@ handle_message(void *arg)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NKC_Initialise(void)
|
||||
{
|
||||
client_credentials = NULL;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NKC_Finalise(void)
|
||||
{
|
||||
if (client_credentials)
|
||||
NKSN_DestroyCertCredentials(client_credentials);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
NKC_Instance
|
||||
NKC_CreateInstance(IPSockAddr *address, const char *name)
|
||||
{
|
||||
@@ -287,10 +279,10 @@ NKC_CreateInstance(IPSockAddr *address, const char *name)
|
||||
inst->destroying = 0;
|
||||
inst->got_response = 0;
|
||||
|
||||
/* Create the credentials with the first client instance and share them
|
||||
with other instances */
|
||||
/* Share the credentials with other client instances */
|
||||
if (!client_credentials)
|
||||
client_credentials = NKSN_CreateCertCredentials(NULL, NULL, CNF_GetNtsTrustedCertFile());
|
||||
client_credentials_refs++;
|
||||
|
||||
return inst;
|
||||
}
|
||||
@@ -300,15 +292,23 @@ NKC_CreateInstance(IPSockAddr *address, const char *name)
|
||||
void
|
||||
NKC_DestroyInstance(NKC_Instance inst)
|
||||
{
|
||||
/* If the resolver is running, destroy the instance later when finished */
|
||||
NKSN_DestroyInstance(inst->session);
|
||||
|
||||
Free(inst->name);
|
||||
|
||||
client_credentials_refs--;
|
||||
if (client_credentials_refs <= 0 && client_credentials) {
|
||||
NKSN_DestroyCertCredentials(client_credentials);
|
||||
client_credentials = NULL;
|
||||
}
|
||||
|
||||
/* If the asynchronous resolver is running, let the handler free
|
||||
the instance later */
|
||||
if (inst->resolving_name) {
|
||||
inst->destroying = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
NKSN_DestroyInstance(inst->session);
|
||||
|
||||
Free(inst->name);
|
||||
Free(inst);
|
||||
}
|
||||
|
||||
@@ -318,24 +318,24 @@ int
|
||||
NKC_Start(NKC_Instance inst)
|
||||
{
|
||||
IPSockAddr local_addr;
|
||||
char label[512];
|
||||
char label[512], *iface;
|
||||
int sock_fd;
|
||||
|
||||
assert(!NKC_IsActive(inst));
|
||||
|
||||
inst->got_response = 0;
|
||||
|
||||
if (!client_credentials) {
|
||||
DEBUG_LOG("Missing client credentials");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Follow the bindacqaddress setting */
|
||||
/* Follow the bindacqaddress and bindacqdevice settings */
|
||||
CNF_GetBindAcquisitionAddress(inst->address.ip_addr.family, &local_addr.ip_addr);
|
||||
if (local_addr.ip_addr.family != inst->address.ip_addr.family)
|
||||
SCK_GetAnyLocalIPAddress(inst->address.ip_addr.family, &local_addr.ip_addr);
|
||||
|
||||
local_addr.port = 0;
|
||||
iface = CNF_GetBindAcquisitionInterface();
|
||||
|
||||
sock_fd = SCK_OpenTcpSocket(&inst->address, &local_addr, 0);
|
||||
sock_fd = SCK_OpenTcpSocket(&inst->address, &local_addr, iface, 0);
|
||||
if (sock_fd < 0)
|
||||
return 0;
|
||||
|
||||
@@ -344,7 +344,7 @@ NKC_Start(NKC_Instance inst)
|
||||
UTI_IPSockAddrToString(&inst->address), inst->name) >= sizeof (label))
|
||||
;
|
||||
|
||||
/* Start a NTS-KE session */
|
||||
/* Start an NTS-KE session */
|
||||
if (!NKSN_StartSession(inst->session, sock_fd, label, client_credentials, CLIENT_TIMEOUT)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
@@ -388,7 +388,7 @@ NKC_GetNtsData(NKC_Instance inst, NKE_Context *context,
|
||||
|
||||
*ntp_address = inst->ntp_address;
|
||||
|
||||
return i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -32,10 +32,6 @@
|
||||
|
||||
typedef struct NKC_Instance_Record *NKC_Instance;
|
||||
|
||||
/* Init and fini functions */
|
||||
extern void NKC_Initialise(void);
|
||||
extern void NKC_Finalise(void);
|
||||
|
||||
/* Create a client NTS-KE instance */
|
||||
extern NKC_Instance NKC_CreateInstance(IPSockAddr *address, const char *name);
|
||||
|
||||
|
||||
277
nts_ke_server.c
277
nts_ke_server.c
@@ -33,10 +33,12 @@
|
||||
#include "array.h"
|
||||
#include "conf.h"
|
||||
#include "clientlog.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "ntp_core.h"
|
||||
#include "nts_ke_session.h"
|
||||
#include "privops.h"
|
||||
#include "siv.h"
|
||||
#include "socket.h"
|
||||
#include "sched.h"
|
||||
@@ -59,7 +61,7 @@
|
||||
|
||||
typedef struct {
|
||||
uint32_t key_id;
|
||||
uint8_t nonce[SERVER_COOKIE_NONCE_LENGTH];
|
||||
unsigned char nonce[SERVER_COOKIE_NONCE_LENGTH];
|
||||
} ServerCookieHeader;
|
||||
|
||||
typedef struct {
|
||||
@@ -87,6 +89,7 @@ static int server_sock_fd4;
|
||||
static int server_sock_fd6;
|
||||
|
||||
static int helper_sock_fd;
|
||||
static int is_helper;
|
||||
|
||||
static int initialised = 0;
|
||||
|
||||
@@ -106,13 +109,15 @@ handle_client(int sock_fd, IPSockAddr *addr)
|
||||
NKSN_Instance inst, *instp;
|
||||
int i;
|
||||
|
||||
/* Leave at least half of the descriptors which can handled by select()
|
||||
to other use */
|
||||
if (sock_fd > FD_SETSIZE / 2) {
|
||||
DEBUG_LOG("Rejected connection from %s (%s)",
|
||||
UTI_IPSockAddrToString(addr), "too many descriptors");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find a slot which is free or has a stopped session */
|
||||
/* Find an unused server slot or one with an already stopped session */
|
||||
for (i = 0, inst = NULL; i < ARR_GetSize(sessions); i++) {
|
||||
instp = ARR_GetElement(sessions, i);
|
||||
if (!*instp) {
|
||||
@@ -132,6 +137,8 @@ handle_client(int sock_fd, IPSockAddr *addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(server_credentials);
|
||||
|
||||
if (!NKSN_StartSession(inst, sock_fd, UTI_IPSockAddrToString(addr),
|
||||
server_credentials, SERVER_TIMEOUT))
|
||||
return 0;
|
||||
@@ -149,6 +156,8 @@ handle_helper_request(int fd, int event, void *arg)
|
||||
IPSockAddr client_addr;
|
||||
int sock_fd;
|
||||
|
||||
/* Receive the helper request with the NTS-KE session socket.
|
||||
With multiple helpers EAGAIN errors are expected here. */
|
||||
message = SCK_ReceiveMessage(fd, SCK_FLAG_MSG_DESCRIPTOR);
|
||||
if (!message)
|
||||
return;
|
||||
@@ -160,16 +169,20 @@ handle_helper_request(int fd, int event, void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
if (message->length != sizeof (HelperRequest)) {
|
||||
DEBUG_LOG("Unexpected message length");
|
||||
if (!initialised) {
|
||||
DEBUG_LOG("Uninitialised helper");
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message->length != sizeof (HelperRequest))
|
||||
LOG_FATAL("Invalid helper request");
|
||||
|
||||
req = message->data;
|
||||
|
||||
/* Extract the server key and client address from the request */
|
||||
/* Extract the current server key and client address from the request */
|
||||
server_keys[current_server_key].id = ntohl(req->key_id);
|
||||
assert(sizeof (server_keys[current_server_key].key) == sizeof (req->key));
|
||||
memcpy(server_keys[current_server_key].key, req->key,
|
||||
sizeof (server_keys[current_server_key].key));
|
||||
UTI_IPNetworkToHost(&req->client_addr, &client_addr.ip_addr);
|
||||
@@ -177,7 +190,7 @@ handle_helper_request(int fd, int event, void *arg)
|
||||
|
||||
if (!SIV_SetKey(server_keys[current_server_key].siv, server_keys[current_server_key].key,
|
||||
SIV_GetKeyLength(SERVER_COOKIE_SIV)))
|
||||
assert(0);
|
||||
LOG_FATAL("Could not set SIV key");
|
||||
|
||||
if (!handle_client(sock_fd, &client_addr)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
@@ -190,14 +203,14 @@ handle_helper_request(int fd, int event, void *arg)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
accept_connection(int server_fd, int event, void *arg)
|
||||
accept_connection(int listening_fd, int event, void *arg)
|
||||
{
|
||||
SCK_Message message;
|
||||
IPSockAddr addr;
|
||||
int log_index, sock_fd;
|
||||
struct timespec now;
|
||||
|
||||
sock_fd = SCK_AcceptConnection(server_fd, &addr);
|
||||
sock_fd = SCK_AcceptConnection(listening_fd, &addr);
|
||||
if (sock_fd < 0)
|
||||
return;
|
||||
|
||||
@@ -209,8 +222,9 @@ accept_connection(int server_fd, int event, void *arg)
|
||||
}
|
||||
|
||||
SCH_GetLastEventTime(&now, NULL, NULL);
|
||||
log_index = CLG_LogNTPAccess(&addr.ip_addr, &now);
|
||||
if (log_index >= 0 && CLG_LimitNTPResponseRate(log_index)) {
|
||||
|
||||
log_index = CLG_LogServiceAccess(CLG_NTSKE, &addr.ip_addr, &now);
|
||||
if (log_index >= 0 && CLG_LimitServiceRate(CLG_NTSKE, log_index)) {
|
||||
DEBUG_LOG("Rejected connection from %s (%s)",
|
||||
UTI_IPSockAddrToString(&addr), "rate limit");
|
||||
SCK_CloseSocket(sock_fd);
|
||||
@@ -222,9 +236,11 @@ accept_connection(int server_fd, int event, void *arg)
|
||||
if (helper_sock_fd != INVALID_SOCK_FD) {
|
||||
HelperRequest req;
|
||||
|
||||
/* Include the current server key and client address in the request */
|
||||
memset(&req, 0, sizeof (req));
|
||||
|
||||
/* Include the current server key and client address in the request */
|
||||
req.key_id = htonl(server_keys[current_server_key].id);
|
||||
assert(sizeof (req.key) == sizeof (server_keys[current_server_key].key));
|
||||
memcpy(req.key, server_keys[current_server_key].key, sizeof (req.key));
|
||||
UTI_IPHostToNetwork(&addr.ip_addr, &req.client_addr);
|
||||
req.client_port = htons(addr.port);
|
||||
@@ -234,7 +250,12 @@ accept_connection(int server_fd, int event, void *arg)
|
||||
message.length = sizeof (req);
|
||||
message.descriptor = sock_fd;
|
||||
|
||||
errno = 0;
|
||||
if (!SCK_SendMessage(helper_sock_fd, &message, SCK_FLAG_MSG_DESCRIPTOR)) {
|
||||
/* If sending failed with EPIPE, it means all helpers closed their end of
|
||||
the socket (e.g. due to a fatal error) */
|
||||
if (errno == EPIPE)
|
||||
LOG_FATAL("NTS-KE helpers failed");
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return;
|
||||
}
|
||||
@@ -253,28 +274,30 @@ accept_connection(int server_fd, int event, void *arg)
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_socket(int family, int port)
|
||||
open_socket(int family)
|
||||
{
|
||||
IPSockAddr local_addr;
|
||||
int sock_fd;
|
||||
int backlog, sock_fd;
|
||||
char *iface;
|
||||
|
||||
if (!SCK_IsFamilySupported(family))
|
||||
if (!SCK_IsIpFamilyEnabled(family))
|
||||
return INVALID_SOCK_FD;
|
||||
|
||||
CNF_GetBindAddress(family, &local_addr.ip_addr);
|
||||
local_addr.port = CNF_GetNtsServerPort();
|
||||
iface = CNF_GetBindNtpInterface();
|
||||
|
||||
if (local_addr.ip_addr.family != family)
|
||||
SCK_GetAnyLocalIPAddress(family, &local_addr.ip_addr);
|
||||
|
||||
local_addr.port = port;
|
||||
|
||||
sock_fd = SCK_OpenTcpSocket(NULL, &local_addr, 0);
|
||||
sock_fd = SCK_OpenTcpSocket(NULL, &local_addr, iface, 0);
|
||||
if (sock_fd < 0) {
|
||||
LOG(LOGS_ERR, "Could not open NTS-KE socket on %s", UTI_IPSockAddrToString(&local_addr));
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
if (!SCK_ListenOnSocket(sock_fd, CNF_GetNtsServerConnections())) {
|
||||
/* Set the maximum number of waiting connections on the socket to the maximum
|
||||
number of concurrent sessions */
|
||||
backlog = MAX(CNF_GetNtsServerProcesses(), 1) * CNF_GetNtsServerConnections();
|
||||
|
||||
if (!SCK_ListenOnSocket(sock_fd, backlog)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
@@ -311,6 +334,15 @@ prepare_response(NKSN_Instance session, int error, int next_protocol, int aead_a
|
||||
datum = htons(error);
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_ERROR, &datum, sizeof (datum)))
|
||||
return 0;
|
||||
} else if (next_protocol < 0) {
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, NULL, 0))
|
||||
return 0;
|
||||
} else if (aead_algorithm < 0) {
|
||||
datum = htons(next_protocol);
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, &datum, sizeof (datum)))
|
||||
return 0;
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, NULL, 0))
|
||||
return 0;
|
||||
} else {
|
||||
datum = htons(next_protocol);
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, &datum, sizeof (datum)))
|
||||
@@ -357,6 +389,8 @@ prepare_response(NKSN_Instance session, int error, int next_protocol, int aead_a
|
||||
static int
|
||||
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;
|
||||
uint16_t data[NKE_MAX_RECORD_BODY_LENGTH / sizeof (uint16_t)];
|
||||
@@ -364,7 +398,7 @@ process_request(NKSN_Instance session)
|
||||
assert(NKE_MAX_RECORD_BODY_LENGTH % sizeof (uint16_t) == 0);
|
||||
assert(sizeof (uint16_t) == 2);
|
||||
|
||||
while (error == -1) {
|
||||
while (error < 0) {
|
||||
if (!NKSN_GetRecord(session, &critical, &type, &length, &data, sizeof (data)))
|
||||
break;
|
||||
|
||||
@@ -374,7 +408,11 @@ process_request(NKSN_Instance session)
|
||||
error = NKE_ERROR_BAD_REQUEST;
|
||||
break;
|
||||
}
|
||||
|
||||
next_protocol_records++;
|
||||
|
||||
for (i = 0; i < MIN(length, sizeof (data)) / 2; i++) {
|
||||
next_protocol_values++;
|
||||
if (ntohs(data[i]) == NKE_NEXT_PROTOCOL_NTPV4)
|
||||
next_protocol = NKE_NEXT_PROTOCOL_NTPV4;
|
||||
}
|
||||
@@ -384,7 +422,11 @@ process_request(NKSN_Instance session)
|
||||
error = NKE_ERROR_BAD_REQUEST;
|
||||
break;
|
||||
}
|
||||
|
||||
aead_algorithm_records++;
|
||||
|
||||
for (i = 0; i < MIN(length, sizeof (data)) / 2; i++) {
|
||||
aead_algorithm_values++;
|
||||
if (ntohs(data[i]) == AEAD_AES_SIV_CMAC_256)
|
||||
aead_algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
}
|
||||
@@ -400,8 +442,12 @@ process_request(NKSN_Instance session)
|
||||
}
|
||||
}
|
||||
|
||||
if (aead_algorithm < 0 || next_protocol < 0)
|
||||
error = NKE_ERROR_BAD_REQUEST;
|
||||
if (error < 0) {
|
||||
if (next_protocol_records != 1 || next_protocol_values < 1 ||
|
||||
(next_protocol == NKE_NEXT_PROTOCOL_NTPV4 &&
|
||||
(aead_algorithm_records != 1 || aead_algorithm_values < 1)))
|
||||
error = NKE_ERROR_BAD_REQUEST;
|
||||
}
|
||||
|
||||
if (!prepare_response(session, error, next_protocol, aead_algorithm))
|
||||
return 0;
|
||||
@@ -426,18 +472,22 @@ generate_key(int index)
|
||||
{
|
||||
int key_length;
|
||||
|
||||
assert(index < MAX_SERVER_KEYS);
|
||||
if (index < 0 || index >= MAX_SERVER_KEYS)
|
||||
assert(0);
|
||||
|
||||
key_length = SIV_GetKeyLength(SERVER_COOKIE_SIV);
|
||||
if (key_length > sizeof (server_keys[index].key))
|
||||
assert(0);
|
||||
|
||||
UTI_GetRandomBytesUrandom(server_keys[index].key, key_length);
|
||||
if (!SIV_SetKey(server_keys[index].siv, server_keys[index].key, key_length))
|
||||
assert(0);
|
||||
|
||||
if (!server_keys[index].siv ||
|
||||
!SIV_SetKey(server_keys[index].siv, server_keys[index].key, key_length))
|
||||
LOG_FATAL("Could not set SIV key");
|
||||
|
||||
UTI_GetRandomBytes(&server_keys[index].id, sizeof (server_keys[index].id));
|
||||
|
||||
/* Encode the index in the lowest bits of the ID */
|
||||
server_keys[index].id &= -1U << KEY_ID_INDEX_BITS;
|
||||
server_keys[index].id |= index;
|
||||
|
||||
@@ -486,6 +536,7 @@ save_keys(void)
|
||||
|
||||
fclose(f);
|
||||
|
||||
/* Rename the temporary file, or remove it if that fails */
|
||||
if (!UTI_RenameTempFile(dump_dir, DUMP_FILENAME, ".tmp", NULL)) {
|
||||
if (!UTI_RemoveFile(dump_dir, DUMP_FILENAME, ".tmp"))
|
||||
;
|
||||
@@ -509,6 +560,7 @@ static void
|
||||
load_keys(void)
|
||||
{
|
||||
char *dump_dir, line[1024], *words[MAX_WORDS];
|
||||
unsigned char key[SIV_MAX_KEY_LENGTH];
|
||||
int i, index, key_length, algorithm;
|
||||
double key_age;
|
||||
FILE *f;
|
||||
@@ -536,15 +588,17 @@ load_keys(void)
|
||||
sscanf(words[0], "%"PRIX32, &id) != 1)
|
||||
goto error;
|
||||
|
||||
index = id % MAX_SERVER_KEYS;
|
||||
|
||||
if (UTI_HexToBytes(words[1], server_keys[index].key,
|
||||
sizeof (server_keys[index].key)) != key_length)
|
||||
if (UTI_HexToBytes(words[1], key, sizeof (key)) != key_length)
|
||||
goto error;
|
||||
|
||||
index = id % MAX_SERVER_KEYS;
|
||||
|
||||
server_keys[index].id = id;
|
||||
assert(sizeof (server_keys[index].key) == sizeof (key));
|
||||
memcpy(server_keys[index].key, key, key_length);
|
||||
|
||||
if (!SIV_SetKey(server_keys[index].siv, server_keys[index].key, key_length))
|
||||
assert(0);
|
||||
LOG_FATAL("Could not set SIV key");
|
||||
|
||||
DEBUG_LOG("Loaded key %"PRIX32, id);
|
||||
|
||||
@@ -575,36 +629,43 @@ key_timeout(void *arg)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
start_helper(int id, int scfilter_level, int main_fd, int helper_fd)
|
||||
run_helper(uid_t uid, gid_t gid, int scfilter_level)
|
||||
{
|
||||
pid_t pid;
|
||||
LOG_Severity log_severity;
|
||||
|
||||
pid = fork();
|
||||
/* Finish minimal initialisation and run using the scheduler loop
|
||||
similarly to the main process */
|
||||
|
||||
if (pid < 0)
|
||||
LOG_FATAL("fork() failed : %s", strerror(errno));
|
||||
DEBUG_LOG("Helper started");
|
||||
|
||||
if (pid > 0)
|
||||
return;
|
||||
/* Suppress a log message about disabled clock control */
|
||||
log_severity = LOG_GetMinSeverity();
|
||||
LOG_SetMinSeverity(LOGS_ERR);
|
||||
|
||||
SCK_CloseSocket(main_fd);
|
||||
SYS_Initialise(0);
|
||||
LOG_SetMinSeverity(log_severity);
|
||||
|
||||
if (!geteuid() && (uid || gid))
|
||||
SYS_DropRoot(uid, gid);
|
||||
|
||||
NKS_Initialise();
|
||||
|
||||
LOG_CloseParentFd();
|
||||
SCH_Reset();
|
||||
SCH_AddFileHandler(helper_fd, SCH_FILE_INPUT, handle_helper_request, NULL);
|
||||
UTI_SetQuitSignalsHandler(helper_signal, 1);
|
||||
if (scfilter_level != 0)
|
||||
SYS_EnableSystemCallFilter(scfilter_level, SYS_NTSKE_HELPER);
|
||||
|
||||
initialised = 1;
|
||||
|
||||
DEBUG_LOG("NTS-KE helper #%d started", id);
|
||||
|
||||
SCH_MainLoop();
|
||||
|
||||
NKS_Finalise();
|
||||
DEBUG_LOG("Helper exiting");
|
||||
|
||||
DEBUG_LOG("NTS-KE helper #%d exiting", id);
|
||||
NKS_Finalise();
|
||||
SCK_Finalise();
|
||||
SYS_Finalise();
|
||||
SCH_Finalise();
|
||||
LCL_Finalise();
|
||||
PRV_Finalise();
|
||||
CNF_Finalise();
|
||||
LOG_Finalise();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -612,15 +673,65 @@ start_helper(int id, int scfilter_level, int main_fd, int helper_fd)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NKS_Initialise(int scfilter_level)
|
||||
NKS_PreInitialise(uid_t uid, gid_t gid, int scfilter_level)
|
||||
{
|
||||
int i, processes, sock_fd1, sock_fd2;
|
||||
char prefix[16];
|
||||
pid_t pid;
|
||||
|
||||
helper_sock_fd = INVALID_SOCK_FD;
|
||||
is_helper = 0;
|
||||
|
||||
if (!CNF_GetNtsServerCertFile() || !CNF_GetNtsServerKeyFile())
|
||||
return;
|
||||
|
||||
processes = CNF_GetNtsServerProcesses();
|
||||
if (processes <= 0)
|
||||
return;
|
||||
|
||||
/* Start helper processes to perform (computationally expensive) NTS-KE
|
||||
sessions with clients on sockets forwarded from the main process */
|
||||
|
||||
sock_fd1 = SCK_OpenUnixSocketPair(0, &sock_fd2);
|
||||
if (sock_fd1 < 0)
|
||||
LOG_FATAL("Could not open socket pair");
|
||||
|
||||
for (i = 0; i < processes; i++) {
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0)
|
||||
LOG_FATAL("fork() failed : %s", strerror(errno));
|
||||
|
||||
if (pid > 0)
|
||||
continue;
|
||||
|
||||
is_helper = 1;
|
||||
|
||||
snprintf(prefix, sizeof (prefix), "nks#%d:", i + 1);
|
||||
LOG_SetDebugPrefix(prefix);
|
||||
LOG_CloseParentFd();
|
||||
|
||||
SCK_CloseSocket(sock_fd1);
|
||||
SCH_AddFileHandler(sock_fd2, SCH_FILE_INPUT, handle_helper_request, NULL);
|
||||
|
||||
run_helper(uid, gid, scfilter_level);
|
||||
}
|
||||
|
||||
SCK_CloseSocket(sock_fd2);
|
||||
helper_sock_fd = sock_fd1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NKS_Initialise(void)
|
||||
{
|
||||
char *cert, *key;
|
||||
int i, processes;
|
||||
double key_delay;
|
||||
int i;
|
||||
|
||||
server_sock_fd4 = INVALID_SOCK_FD;
|
||||
server_sock_fd6 = INVALID_SOCK_FD;
|
||||
helper_sock_fd = INVALID_SOCK_FD;
|
||||
|
||||
cert = CNF_GetNtsServerCertFile();
|
||||
key = CNF_GetNtsServerKeyFile();
|
||||
@@ -628,19 +739,20 @@ NKS_Initialise(int scfilter_level)
|
||||
if (!cert || !key)
|
||||
return;
|
||||
|
||||
server_credentials = NKSN_CreateCertCredentials(cert, key, NULL);
|
||||
if (!server_credentials)
|
||||
return;
|
||||
if (helper_sock_fd == INVALID_SOCK_FD) {
|
||||
server_credentials = NKSN_CreateCertCredentials(cert, key, NULL);
|
||||
if (!server_credentials)
|
||||
return;
|
||||
} else {
|
||||
server_credentials = NULL;
|
||||
}
|
||||
|
||||
sessions = ARR_CreateInstance(sizeof (NKSN_Instance));
|
||||
for (i = 0; i < CNF_GetNtsServerConnections(); i++)
|
||||
*(NKSN_Instance *)ARR_GetNewElement(sessions) = NULL;
|
||||
for (i = 0; i < MAX_SERVER_KEYS; i++)
|
||||
server_keys[i].siv = NULL;
|
||||
|
||||
server_sock_fd4 = open_socket(IPADDR_INET4, CNF_GetNtsServerPort());
|
||||
server_sock_fd6 = open_socket(IPADDR_INET6, CNF_GetNtsServerPort());
|
||||
|
||||
/* Generate random keys, even if they will be replaced by reloaded keys,
|
||||
or unused (in the helper) */
|
||||
for (i = 0; i < MAX_SERVER_KEYS; i++) {
|
||||
server_keys[i].siv = SIV_CreateInstance(SERVER_COOKIE_SIV);
|
||||
generate_key(i);
|
||||
@@ -648,29 +760,18 @@ NKS_Initialise(int scfilter_level)
|
||||
|
||||
current_server_key = MAX_SERVER_KEYS - 1;
|
||||
|
||||
load_keys();
|
||||
if (!is_helper) {
|
||||
server_sock_fd4 = open_socket(IPADDR_INET4);
|
||||
server_sock_fd6 = open_socket(IPADDR_INET6);
|
||||
|
||||
key_rotation_interval = MAX(CNF_GetNtsRotate(), 0);
|
||||
load_keys();
|
||||
|
||||
if (key_rotation_interval > 0) {
|
||||
key_delay = key_rotation_interval - (SCH_GetLastEventMonoTime() - last_server_key_ts);
|
||||
SCH_AddTimeoutByDelay(MAX(key_delay, 0.0), key_timeout, NULL);
|
||||
}
|
||||
key_rotation_interval = MAX(CNF_GetNtsRotate(), 0);
|
||||
|
||||
processes = CNF_GetNtsServerProcesses();
|
||||
|
||||
if (processes > 0) {
|
||||
int sock_fd1, sock_fd2;
|
||||
|
||||
sock_fd1 = SCK_OpenUnixSocketPair(0, &sock_fd2);
|
||||
if (sock_fd1 < 0)
|
||||
LOG_FATAL("Could not open socket pair");
|
||||
|
||||
for (i = 0; i < processes; i++)
|
||||
start_helper(i + 1, scfilter_level, sock_fd1, sock_fd2);
|
||||
|
||||
SCK_CloseSocket(sock_fd2);
|
||||
helper_sock_fd = sock_fd1;
|
||||
if (key_rotation_interval > 0) {
|
||||
key_delay = key_rotation_interval - (SCH_GetLastEventMonoTime() - last_server_key_ts);
|
||||
SCH_AddTimeoutByDelay(MAX(key_delay, 0.0), key_timeout, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
initialised = 1;
|
||||
@@ -687,6 +788,7 @@ NKS_Finalise(void)
|
||||
return;
|
||||
|
||||
if (helper_sock_fd != INVALID_SOCK_FD) {
|
||||
/* Send the helpers a request to exit */
|
||||
for (i = 0; i < CNF_GetNtsServerProcesses(); i++) {
|
||||
if (!SCK_Send(helper_sock_fd, "", 1, 0))
|
||||
;
|
||||
@@ -698,11 +800,11 @@ NKS_Finalise(void)
|
||||
if (server_sock_fd6 != INVALID_SOCK_FD)
|
||||
SCK_CloseSocket(server_sock_fd6);
|
||||
|
||||
save_keys();
|
||||
for (i = 0; i < MAX_SERVER_KEYS; i++) {
|
||||
if (server_keys[i].siv != NULL)
|
||||
SIV_DestroyInstance(server_keys[i].siv);
|
||||
}
|
||||
if (!is_helper)
|
||||
save_keys();
|
||||
|
||||
for (i = 0; i < MAX_SERVER_KEYS; i++)
|
||||
SIV_DestroyInstance(server_keys[i].siv);
|
||||
|
||||
for (i = 0; i < ARR_GetSize(sessions); i++) {
|
||||
NKSN_Instance session = *(NKSN_Instance *)ARR_GetElement(sessions, i);
|
||||
@@ -711,7 +813,8 @@ NKS_Finalise(void)
|
||||
}
|
||||
ARR_DestroyInstance(sessions);
|
||||
|
||||
NKSN_DestroyCertCredentials(server_credentials);
|
||||
if (server_credentials)
|
||||
NKSN_DestroyCertCredentials(server_credentials);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -808,7 +911,7 @@ NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Context *context)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cookie->length <= sizeof (*header)) {
|
||||
if (cookie->length <= (int)sizeof (*header)) {
|
||||
DEBUG_LOG("Invalid cookie length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
#include "nts_ke.h"
|
||||
|
||||
/* Init and fini functions */
|
||||
extern void NKS_Initialise(int scfilter_level);
|
||||
extern void NKS_PreInitialise(uid_t uid, gid_t gid, int scfilter_level);
|
||||
extern void NKS_Initialise(void);
|
||||
extern void NKS_Finalise(void);
|
||||
|
||||
/* Save the current server keys */
|
||||
|
||||
101
nts_ke_session.c
101
nts_ke_session.c
@@ -81,7 +81,6 @@ struct NKSN_Instance_Record {
|
||||
|
||||
struct Message message;
|
||||
int new_message;
|
||||
int ended_message;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
@@ -110,6 +109,8 @@ add_record(struct Message *message, int critical, int type, const void *body, in
|
||||
{
|
||||
struct RecordHeader header;
|
||||
|
||||
assert(message->length <= sizeof (message->data));
|
||||
|
||||
if (body_length < 0 || body_length > 0xffff || type < 0 || type > 0x7fff ||
|
||||
message->length + sizeof (header) + body_length > sizeof (message->data))
|
||||
return 0;
|
||||
@@ -153,6 +154,7 @@ get_record(struct Message *message, int *critical, int *type, int *body_length,
|
||||
|
||||
blen = ntohs(header.body_length);
|
||||
rlen = sizeof (header) + blen;
|
||||
assert(blen >= 0 && rlen > 0);
|
||||
|
||||
if (message->length < message->parsed + rlen)
|
||||
return 0;
|
||||
@@ -215,7 +217,8 @@ create_tls_session(int server_mode, int sock_fd, const char *server_name,
|
||||
unsigned int flags;
|
||||
int r;
|
||||
|
||||
r = gnutls_init(&session, GNUTLS_NONBLOCK | (server_mode ? GNUTLS_SERVER : GNUTLS_CLIENT));
|
||||
r = gnutls_init(&session, GNUTLS_NONBLOCK | GNUTLS_NO_TICKETS |
|
||||
(server_mode ? GNUTLS_SERVER : GNUTLS_CLIENT));
|
||||
if (r < 0) {
|
||||
LOG(LOGS_ERR, "Could not %s TLS session : %s", "create", gnutls_strerror(r));
|
||||
return NULL;
|
||||
@@ -302,33 +305,25 @@ session_timeout(void *arg)
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
get_socket_error(int sock_fd)
|
||||
check_alpn(NKSN_Instance inst)
|
||||
{
|
||||
int optval;
|
||||
socklen_t optlen = sizeof (optval);
|
||||
gnutls_datum_t alpn;
|
||||
|
||||
if (getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) {
|
||||
DEBUG_LOG("getsockopt() failed : %s", strerror(errno));
|
||||
return EINVAL;
|
||||
}
|
||||
if (gnutls_alpn_get_selected_protocol(inst->tls_session, &alpn) < 0 ||
|
||||
alpn.size != sizeof (NKE_ALPN_NAME) - 1 ||
|
||||
memcmp(alpn.data, NKE_ALPN_NAME, sizeof (NKE_ALPN_NAME) - 1) != 0)
|
||||
return 0;
|
||||
|
||||
return optval;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_alpn(NKSN_Instance inst)
|
||||
static void
|
||||
set_input_output(NKSN_Instance inst, int output)
|
||||
{
|
||||
gnutls_datum_t alpn;
|
||||
int r;
|
||||
|
||||
r = gnutls_alpn_get_selected_protocol(inst->tls_session, &alpn);
|
||||
if (r < 0 || alpn.size != sizeof (NKE_ALPN_NAME) - 1 ||
|
||||
strncmp((const char *)alpn.data, NKE_ALPN_NAME, sizeof (NKE_ALPN_NAME) - 1))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
SCH_SetFileHandlerEvent(inst->sock_fd, SCH_FILE_INPUT, !output);
|
||||
SCH_SetFileHandlerEvent(inst->sock_fd, SCH_FILE_OUTPUT, output);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -354,7 +349,7 @@ change_state(NKSN_Instance inst, KeState state)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
SCH_SetFileHandlerEvent(inst->sock_fd, SCH_FILE_OUTPUT, output);
|
||||
set_input_output(inst, output);
|
||||
|
||||
inst->state = state;
|
||||
}
|
||||
@@ -375,9 +370,11 @@ handle_event(NKSN_Instance inst, int event)
|
||||
if (event != SCH_FILE_OUTPUT)
|
||||
return 0;
|
||||
|
||||
r = get_socket_error(inst->sock_fd);
|
||||
/* Get the socket error */
|
||||
if (!SCK_GetIntOption(inst->sock_fd, SOL_SOCKET, SO_ERROR, &r))
|
||||
r = EINVAL;
|
||||
|
||||
if (r) {
|
||||
if (r != 0) {
|
||||
LOG(LOGS_ERR, "Could not connect to %s : %s", inst->label, strerror(r));
|
||||
stop_session(inst);
|
||||
return 0;
|
||||
@@ -393,8 +390,22 @@ handle_event(NKSN_Instance inst, int event)
|
||||
|
||||
if (r < 0) {
|
||||
if (gnutls_error_is_fatal(r)) {
|
||||
gnutls_datum_t cert_error;
|
||||
|
||||
/* Get a description of verification errors */
|
||||
if (r != GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR ||
|
||||
gnutls_certificate_verification_status_print(
|
||||
gnutls_session_get_verify_cert_status(inst->tls_session),
|
||||
gnutls_certificate_type_get(inst->tls_session), &cert_error, 0) < 0)
|
||||
cert_error.data = NULL;
|
||||
|
||||
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR,
|
||||
"TLS handshake with %s failed : %s", inst->label, gnutls_strerror(r));
|
||||
"TLS handshake with %s failed : %s%s%s", inst->label, gnutls_strerror(r),
|
||||
cert_error.data ? " " : "", cert_error.data ? (const char *)cert_error.data : "");
|
||||
|
||||
if (cert_error.data)
|
||||
gnutls_free(cert_error.data);
|
||||
|
||||
stop_session(inst);
|
||||
|
||||
/* Increase the retry interval if the handshake did not fail due
|
||||
@@ -406,8 +417,7 @@ handle_event(NKSN_Instance inst, int event)
|
||||
}
|
||||
|
||||
/* Disable output when the handshake is trying to receive data */
|
||||
SCH_SetFileHandlerEvent(inst->sock_fd, SCH_FILE_OUTPUT,
|
||||
gnutls_record_get_direction(inst->tls_session));
|
||||
set_input_output(inst, gnutls_record_get_direction(inst->tls_session));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -432,6 +442,7 @@ handle_event(NKSN_Instance inst, int event)
|
||||
|
||||
case KE_SEND:
|
||||
assert(inst->new_message && message->complete);
|
||||
assert(message->length <= sizeof (message->data) && message->length > message->sent);
|
||||
|
||||
r = gnutls_record_send(inst->tls_session, &message->data[message->sent],
|
||||
message->length - message->sent);
|
||||
@@ -499,7 +510,9 @@ handle_event(NKSN_Instance inst, int event)
|
||||
|
||||
/* Server will send a response to the client */
|
||||
change_state(inst, inst->server ? KE_SEND : KE_SHUTDOWN);
|
||||
break;
|
||||
|
||||
/* Return success to process the received message */
|
||||
return 1;
|
||||
|
||||
case KE_SHUTDOWN:
|
||||
r = gnutls_bye(inst->tls_session, GNUTLS_SHUT_RDWR);
|
||||
@@ -512,8 +525,7 @@ handle_event(NKSN_Instance inst, int event)
|
||||
}
|
||||
|
||||
/* Disable output when the TLS shutdown is trying to receive data */
|
||||
SCH_SetFileHandlerEvent(inst->sock_fd, SCH_FILE_OUTPUT,
|
||||
gnutls_record_get_direction(inst->tls_session));
|
||||
set_input_output(inst, gnutls_record_get_direction(inst->tls_session));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -525,9 +537,8 @@ handle_event(NKSN_Instance inst, int event)
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -540,6 +551,9 @@ read_write_socket(int fd, int event, void *arg)
|
||||
if (!handle_event(inst, event))
|
||||
return;
|
||||
|
||||
/* A valid message was received. Call the handler to process the message,
|
||||
and prepare a response if it is a server. */
|
||||
|
||||
reset_message_parsing(&inst->message);
|
||||
|
||||
if (!(inst->handler)(inst->handler_arg)) {
|
||||
@@ -588,16 +602,19 @@ init_gnutls(void)
|
||||
if (r < 0)
|
||||
LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
|
||||
|
||||
/* NTS specification requires TLS1.3 or later */
|
||||
/* Prepare a priority cache for server and client NTS-KE sessions
|
||||
(the NTS specification requires TLS1.3 or later) */
|
||||
r = gnutls_priority_init2(&priority_cache,
|
||||
"-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.2",
|
||||
"-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.2:-VERS-DTLS-ALL",
|
||||
NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND);
|
||||
if (r < 0)
|
||||
LOG_FATAL("Could not initialise %s : %s", "priority cache", gnutls_strerror(r));
|
||||
|
||||
/* Use our clock instead of the system clock in certificate verification */
|
||||
gnutls_global_set_time_function(get_time);
|
||||
|
||||
gnutls_initialised = 1;
|
||||
DEBUG_LOG("Initialised");
|
||||
|
||||
LCL_AddParameterChangeHandler(handle_step, NULL);
|
||||
}
|
||||
@@ -607,13 +624,15 @@ init_gnutls(void)
|
||||
static void
|
||||
deinit_gnutls(void)
|
||||
{
|
||||
assert(gnutls_initialised);
|
||||
if (!gnutls_initialised || credentials_counter > 0)
|
||||
return;
|
||||
|
||||
LCL_RemoveParameterChangeHandler(handle_step, NULL);
|
||||
|
||||
gnutls_priority_deinit(priority_cache);
|
||||
gnutls_global_deinit();
|
||||
gnutls_initialised = 0;
|
||||
DEBUG_LOG("Deinitialised");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -658,6 +677,7 @@ error:
|
||||
LOG(LOGS_ERR, "Could not set credentials : %s", gnutls_strerror(r));
|
||||
if (credentials)
|
||||
gnutls_certificate_free_credentials(credentials);
|
||||
deinit_gnutls();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -668,9 +688,6 @@ NKSN_DestroyCertCredentials(void *credentials)
|
||||
{
|
||||
gnutls_certificate_free_credentials(credentials);
|
||||
credentials_counter--;
|
||||
if (credentials_counter != 0)
|
||||
return;
|
||||
|
||||
deinit_gnutls();
|
||||
}
|
||||
|
||||
@@ -688,7 +705,7 @@ NKSN_CreateInstance(int server_mode, const char *server_name,
|
||||
inst->server_name = server_name ? Strdup(server_name) : NULL;
|
||||
inst->handler = handler;
|
||||
inst->handler_arg = handler_arg;
|
||||
/* Replace NULL arg with the session itself */
|
||||
/* Replace a NULL argument with the session itself */
|
||||
if (!inst->handler_arg)
|
||||
inst->handler_arg = inst;
|
||||
|
||||
@@ -735,7 +752,6 @@ NKSN_StartSession(NKSN_Instance inst, int sock_fd, const char *label,
|
||||
|
||||
reset_message(&inst->message);
|
||||
inst->new_message = 0;
|
||||
inst->ended_message = 0;
|
||||
|
||||
change_state(inst, inst->server ? KE_HANDSHAKE : KE_WAIT_CONNECT);
|
||||
|
||||
@@ -769,6 +785,7 @@ NKSN_EndMessage(NKSN_Instance inst)
|
||||
{
|
||||
assert(!inst->message.complete);
|
||||
|
||||
/* Terminate the message */
|
||||
if (!add_record(&inst->message, 1, NKE_RECORD_END_OF_MESSAGE, NULL, 0))
|
||||
return 0;
|
||||
|
||||
@@ -787,9 +804,13 @@ NKSN_GetRecord(NKSN_Instance inst, int *critical, int *type, int *body_length,
|
||||
|
||||
assert(inst->message.complete);
|
||||
|
||||
if (body_length)
|
||||
*body_length = 0;
|
||||
|
||||
if (!get_record(&inst->message, critical, &type2, body_length, body, buffer_length))
|
||||
return 0;
|
||||
|
||||
/* Hide the end-of-message record */
|
||||
if (type2 == NKE_RECORD_END_OF_MESSAGE)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
typedef struct NKSN_Instance_Record *NKSN_Instance;
|
||||
|
||||
/* Handler for received NTS-KE messages. A non-zero return code stops
|
||||
/* Handler for received NTS-KE messages. A zero return code stops
|
||||
the session. */
|
||||
typedef int (*NKSN_MessageHandler)(void *arg);
|
||||
|
||||
|
||||
@@ -102,6 +102,10 @@ 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);
|
||||
|
||||
memcpy(body, nonce, nonce_length);
|
||||
memset(body + nonce_length, 0, nonce_padding);
|
||||
|
||||
@@ -128,11 +132,14 @@ NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, in
|
||||
void *ef_body;
|
||||
struct AuthHeader *header;
|
||||
|
||||
if (buffer_length < 0)
|
||||
return 0;
|
||||
|
||||
if (!NEF_ParseField(packet, info->length, ef_start,
|
||||
NULL, &ef_type, &ef_body, &ef_body_length))
|
||||
return 0;
|
||||
|
||||
if (ef_type != NTP_EF_NTS_AUTH_AND_EEF)
|
||||
if (ef_type != NTP_EF_NTS_AUTH_AND_EEF || ef_body_length < sizeof (*header))
|
||||
return 0;
|
||||
|
||||
header = ef_body;
|
||||
@@ -145,7 +152,7 @@ NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, in
|
||||
return 0;
|
||||
|
||||
nonce = (unsigned char *)(header + 1);
|
||||
ciphertext = (unsigned char *)(header + 1) + get_padded_length(nonce_length);
|
||||
ciphertext = nonce + get_padded_length(nonce_length);
|
||||
|
||||
siv_tag_length = SIV_GetTagLength(siv);
|
||||
|
||||
@@ -163,8 +170,9 @@ NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, in
|
||||
}
|
||||
|
||||
*plaintext_length = ciphertext_length - siv_tag_length;
|
||||
assert(*plaintext_length >= 0);
|
||||
|
||||
if (!SIV_Decrypt(siv, nonce, nonce_length, packet, info->length - ef_body_length - 4,
|
||||
if (!SIV_Decrypt(siv, nonce, nonce_length, packet, ef_start,
|
||||
ciphertext, ciphertext_length, plaintext, *plaintext_length)) {
|
||||
DEBUG_LOG("SIV decrypt failed");
|
||||
return 0;
|
||||
|
||||
105
nts_ntp_client.c
105
nts_ntp_client.c
@@ -43,8 +43,10 @@
|
||||
#include "siv.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Maximum length of all cookies to avoid IP fragmentation */
|
||||
#define MAX_TOTAL_COOKIE_LENGTH (8 * 108)
|
||||
|
||||
/* Magic string of files containing keys and cookies */
|
||||
#define DUMP_IDENTIFIER "NNC0\n"
|
||||
|
||||
struct NNC_Instance_Record {
|
||||
@@ -60,6 +62,7 @@ struct NNC_Instance_Record {
|
||||
double last_nke_success;
|
||||
|
||||
NKE_Context context;
|
||||
unsigned int context_id;
|
||||
NKE_Cookie cookies[NTS_MAX_COOKIES];
|
||||
int num_cookies;
|
||||
int cookie_index;
|
||||
@@ -85,6 +88,8 @@ reset_instance(NNC_Instance inst)
|
||||
inst->last_nke_success = 0.0;
|
||||
|
||||
memset(&inst->context, 0, sizeof (inst->context));
|
||||
inst->context_id = 0;
|
||||
memset(inst->cookies, 0, sizeof (inst->cookies));
|
||||
inst->num_cookies = 0;
|
||||
inst->cookie_index = 0;
|
||||
inst->nak_response = 0;
|
||||
@@ -134,17 +139,15 @@ NNC_DestroyInstance(NNC_Instance inst)
|
||||
static int
|
||||
check_cookies(NNC_Instance inst)
|
||||
{
|
||||
/* Force NKE if a NAK was received since last valid auth */
|
||||
if (inst->nak_response && !inst->ok_response && inst->num_cookies > 0) {
|
||||
/* Force a new NTS-KE session if a NAK was received without a valid response,
|
||||
or the keys encrypting the cookies need to be refreshed */
|
||||
if (inst->num_cookies > 0 &&
|
||||
((inst->nak_response && !inst->ok_response) ||
|
||||
SCH_GetLastEventMonoTime() - inst->last_nke_success > CNF_GetNtsRefresh())) {
|
||||
inst->num_cookies = 0;
|
||||
DEBUG_LOG("Dropped cookies");
|
||||
}
|
||||
|
||||
/* Force NKE if the keys encrypting the cookies are too old */
|
||||
if (inst->num_cookies > 0 &&
|
||||
SCH_GetLastEventMonoTime() - inst->last_nke_success > CNF_GetNtsRefresh())
|
||||
inst->num_cookies = 0;
|
||||
|
||||
return inst->num_cookies > 0;
|
||||
}
|
||||
|
||||
@@ -201,10 +204,11 @@ get_cookies(NNC_Instance inst)
|
||||
double now;
|
||||
int got_data;
|
||||
|
||||
assert(!check_cookies(inst));
|
||||
assert(inst->num_cookies == 0);
|
||||
|
||||
now = SCH_GetLastEventMonoTime();
|
||||
|
||||
/* Create and start a new NTS-KE session if not already present */
|
||||
if (!inst->nke) {
|
||||
if (now < inst->next_nke_attempt) {
|
||||
DEBUG_LOG("Limiting NTS-KE request rate (%f seconds)",
|
||||
@@ -229,9 +233,13 @@ get_cookies(NNC_Instance inst)
|
||||
|
||||
update_next_nke_attempt(inst, now);
|
||||
|
||||
/* Wait until the session stops */
|
||||
if (NKC_IsActive(inst->nke))
|
||||
return 0;
|
||||
|
||||
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,
|
||||
inst->cookies, &inst->num_cookies, NTS_MAX_COOKIES,
|
||||
&ntp_address);
|
||||
@@ -246,17 +254,20 @@ get_cookies(NNC_Instance inst)
|
||||
SIV_DestroyInstance(inst->siv);
|
||||
inst->siv = NULL;
|
||||
|
||||
inst->context_id++;
|
||||
|
||||
/* Force a new session if the NTP address is used by another source, with
|
||||
an expectation that it will eventually get a non-conflicting address */
|
||||
if (!set_ntp_address(inst, &ntp_address)) {
|
||||
inst->num_cookies = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inst->last_nke_success = now;
|
||||
inst->cookie_index = 0;
|
||||
|
||||
inst->nak_response = 0;
|
||||
|
||||
inst->last_nke_success = now;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -265,11 +276,13 @@ get_cookies(NNC_Instance inst)
|
||||
int
|
||||
NNC_PrepareForAuth(NNC_Instance inst)
|
||||
{
|
||||
/* Try to reload saved keys and cookies (once for the NTS-KE address) */
|
||||
if (!inst->load_attempt) {
|
||||
load_cookies(inst);
|
||||
inst->load_attempt = 1;
|
||||
}
|
||||
|
||||
/* Get new cookies if there are not any, or they are no longer usable */
|
||||
if (!check_cookies(inst)) {
|
||||
if (!get_cookies(inst))
|
||||
return 0;
|
||||
@@ -284,8 +297,9 @@ NNC_PrepareForAuth(NNC_Instance inst)
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_GetRandomBytes(&inst->uniq_id, sizeof (inst->uniq_id));
|
||||
UTI_GetRandomBytes(&inst->nonce, sizeof (inst->nonce));
|
||||
/* Prepare data for NNC_GenerateRequestAuth() */
|
||||
UTI_GetRandomBytes(inst->uniq_id, sizeof (inst->uniq_id));
|
||||
UTI_GetRandomBytes(inst->nonce, sizeof (inst->nonce));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -311,7 +325,7 @@ NNC_GenerateRequestAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
MAX_TOTAL_COOKIE_LENGTH / (cookie->length + 4));
|
||||
|
||||
if (!NEF_AddField(packet, info, NTP_EF_NTS_UNIQUE_IDENTIFIER,
|
||||
&inst->uniq_id, sizeof (inst->uniq_id)))
|
||||
inst->uniq_id, sizeof (inst->uniq_id)))
|
||||
return 0;
|
||||
|
||||
if (!NEF_AddField(packet, info, NTP_EF_NTS_COOKIE,
|
||||
@@ -331,6 +345,7 @@ NNC_GenerateRequestAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
|
||||
inst->num_cookies--;
|
||||
inst->cookie_index = (inst->cookie_index + 1) % NTS_MAX_COOKIES;
|
||||
inst->nak_response = 0;
|
||||
inst->ok_response = 0;
|
||||
|
||||
return 1;
|
||||
@@ -338,6 +353,23 @@ NNC_GenerateRequestAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
parse_encrypted_efs(NNC_Instance inst, unsigned char *plaintext, int length)
|
||||
{
|
||||
int ef_length, parsed;
|
||||
|
||||
for (parsed = 0; parsed < length; parsed += ef_length) {
|
||||
if (!NEF_ParseSingleField(plaintext, length, parsed, &ef_length, NULL, NULL, NULL)) {
|
||||
DEBUG_LOG("Could not parse encrypted EF");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
extract_cookies(NNC_Instance inst, unsigned char *plaintext, int length)
|
||||
{
|
||||
@@ -349,7 +381,7 @@ extract_cookies(NNC_Instance inst, unsigned char *plaintext, int length)
|
||||
for (parsed = 0; parsed < length; parsed += ef_length) {
|
||||
if (!NEF_ParseSingleField(plaintext, length, parsed,
|
||||
&ef_length, &ef_type, &ef_body, &ef_body_length))
|
||||
break;
|
||||
return 0;
|
||||
|
||||
if (ef_type != NTP_EF_NTS_COOKIE)
|
||||
continue;
|
||||
@@ -365,6 +397,9 @@ extract_cookies(NNC_Instance inst, unsigned char *plaintext, int length)
|
||||
continue;
|
||||
|
||||
index = (inst->cookie_index + inst->num_cookies) % NTS_MAX_COOKIES;
|
||||
assert(index >= 0 && index < NTS_MAX_COOKIES);
|
||||
assert(sizeof (inst->cookies) / sizeof (inst->cookies[0]) == NTS_MAX_COOKIES);
|
||||
|
||||
memcpy(inst->cookies[index].cookie, ef_body, ef_body_length);
|
||||
inst->cookies[index].length = ef_body_length;
|
||||
inst->num_cookies++;
|
||||
@@ -391,7 +426,7 @@ NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
if (info->ext_fields == 0 || info->mode != MODE_SERVER)
|
||||
return 0;
|
||||
|
||||
/* Accept only one response per request */
|
||||
/* Accept at most one response per request */
|
||||
if (inst->ok_response)
|
||||
return 0;
|
||||
|
||||
@@ -404,7 +439,8 @@ NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
for (parsed = NTP_HEADER_LENGTH; parsed < info->length; parsed += ef_length) {
|
||||
if (!NEF_ParseField(packet, info->length, parsed,
|
||||
&ef_length, &ef_type, &ef_body, &ef_body_length))
|
||||
break;
|
||||
/* This is not expected as the packet already passed NAU_ParsePacket() */
|
||||
return 0;
|
||||
|
||||
switch (ef_type) {
|
||||
case NTP_EF_NTS_UNIQUE_IDENTIFIER:
|
||||
@@ -428,6 +464,9 @@ NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
plaintext, sizeof (plaintext), &plaintext_length))
|
||||
return 0;
|
||||
|
||||
if (!parse_encrypted_efs(inst, plaintext, plaintext_length))
|
||||
return 0;
|
||||
|
||||
has_valid_auth = 1;
|
||||
break;
|
||||
default:
|
||||
@@ -507,9 +546,9 @@ save_cookies(NNC_Instance inst)
|
||||
context_time = inst->last_nke_success - SCH_GetLastEventMonoTime();
|
||||
context_time += UTI_TimespecToDouble(&now);
|
||||
|
||||
if (fprintf(f, "%s%.1f\n%s %d\n%d ",
|
||||
if (fprintf(f, "%s%.1f\n%s %d\n%u %d ",
|
||||
DUMP_IDENTIFIER, context_time, UTI_IPToString(&inst->ntp_address->ip_addr),
|
||||
inst->ntp_address->port, (int)inst->context.algorithm) < 0 ||
|
||||
inst->ntp_address->port, inst->context_id, (int)inst->context.algorithm) < 0 ||
|
||||
!UTI_BytesToHex(inst->context.s2c.key, inst->context.s2c.length, buf, sizeof (buf)) ||
|
||||
fprintf(f, "%s ", buf) < 0 ||
|
||||
!UTI_BytesToHex(inst->context.c2s.key, inst->context.c2s.length, buf, sizeof (buf)) ||
|
||||
@@ -538,12 +577,13 @@ error:
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define MAX_WORDS 3
|
||||
#define MAX_WORDS 4
|
||||
|
||||
static void
|
||||
load_cookies(NNC_Instance inst)
|
||||
{
|
||||
char line[2 * NKE_MAX_COOKIE_LENGTH + 2], *dump_dir, *filename, *words[MAX_WORDS];
|
||||
unsigned int context_id;
|
||||
int i, algorithm, port;
|
||||
double context_time;
|
||||
struct timespec now;
|
||||
@@ -573,14 +613,14 @@ load_cookies(NNC_Instance inst)
|
||||
sscanf(words[0], "%lf", &context_time) != 1 ||
|
||||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 2 ||
|
||||
!UTI_StringToIP(words[0], &ntp_addr.ip_addr) || sscanf(words[1], "%d", &port) != 1 ||
|
||||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 3 ||
|
||||
sscanf(words[0], "%d", &algorithm) != 1)
|
||||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 4 ||
|
||||
sscanf(words[0], "%u", &context_id) != 1 || sscanf(words[1], "%d", &algorithm) != 1)
|
||||
goto error;
|
||||
|
||||
inst->context.algorithm = algorithm;
|
||||
inst->context.s2c.length = UTI_HexToBytes(words[1], inst->context.s2c.key,
|
||||
inst->context.s2c.length = UTI_HexToBytes(words[2], inst->context.s2c.key,
|
||||
sizeof (inst->context.s2c.key));
|
||||
inst->context.c2s.length = UTI_HexToBytes(words[2], inst->context.c2s.key,
|
||||
inst->context.c2s.length = UTI_HexToBytes(words[3], inst->context.c2s.key,
|
||||
sizeof (inst->context.c2s.key));
|
||||
|
||||
if (inst->context.s2c.length != SIV_GetKeyLength(algorithm) ||
|
||||
@@ -608,6 +648,7 @@ load_cookies(NNC_Instance inst)
|
||||
if (context_time > 0)
|
||||
context_time = 0;
|
||||
inst->last_nke_success = context_time + SCH_GetLastEventMonoTime();
|
||||
inst->context_id = context_id;
|
||||
|
||||
DEBUG_LOG("Loaded %d cookies for %s", i, filename);
|
||||
return;
|
||||
@@ -627,3 +668,21 @@ NNC_DumpData(NNC_Instance inst)
|
||||
{
|
||||
save_cookies(inst);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NNC_GetReport(NNC_Instance inst, RPT_AuthReport *report)
|
||||
{
|
||||
report->key_id = inst->context_id;
|
||||
report->key_type = inst->context.algorithm;
|
||||
report->key_length = 8 * inst->context.s2c.length;
|
||||
report->ke_attempts = inst->nke_attempts;
|
||||
if (report->key_length > 0)
|
||||
report->last_ke_ago = SCH_GetLastEventMonoTime() - inst->last_nke_success;
|
||||
else
|
||||
report->last_ke_ago = -1;
|
||||
report->cookies = inst->num_cookies;
|
||||
report->cookie_length = inst->num_cookies > 0 ? inst->cookies[inst->cookie_index].length : 0;
|
||||
report->nak = inst->nak_response;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "addressing.h"
|
||||
#include "ntp.h"
|
||||
#include "reports.h"
|
||||
|
||||
typedef struct NNC_Instance_Record *NNC_Instance;
|
||||
|
||||
@@ -45,4 +46,6 @@ extern void NNC_ChangeAddress(NNC_Instance inst, IPAddr *address);
|
||||
|
||||
extern void NNC_DumpData(NNC_Instance inst);
|
||||
|
||||
extern void NNC_GetReport(NNC_Instance inst, RPT_AuthReport *report);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -67,6 +67,8 @@ NNS_Initialise(void)
|
||||
|
||||
server = Malloc(sizeof (struct NtsServer));
|
||||
server->siv = SIV_CreateInstance(SERVER_SIV);
|
||||
if (!server->siv)
|
||||
LOG_FATAL("Could not initialise SIV cipher");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -110,15 +112,18 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
||||
for (parsed = NTP_HEADER_LENGTH; parsed < info->length; parsed += ef_length) {
|
||||
if (!NEF_ParseField(packet, info->length, parsed,
|
||||
&ef_length, &ef_type, &ef_body, &ef_body_length))
|
||||
break;
|
||||
/* This is not expected as the packet already passed NAU_ParsePacket() */
|
||||
return 0;
|
||||
|
||||
switch (ef_type) {
|
||||
case NTP_EF_NTS_UNIQUE_IDENTIFIER:
|
||||
has_uniq_id = 1;
|
||||
break;
|
||||
case NTP_EF_NTS_COOKIE:
|
||||
if (has_cookie || ef_body_length > sizeof (cookie.cookie))
|
||||
if (has_cookie || ef_body_length > sizeof (cookie.cookie)) {
|
||||
DEBUG_LOG("Unexpected cookie/length");
|
||||
return 0;
|
||||
}
|
||||
cookie.length = ef_body_length;
|
||||
memcpy(cookie.cookie, ef_body, ef_body_length);
|
||||
has_cookie = 1;
|
||||
@@ -133,6 +138,11 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
||||
cookie_length = ef_body_length;
|
||||
break;
|
||||
case NTP_EF_NTS_AUTH_AND_EEF:
|
||||
if (parsed + ef_length != info->length) {
|
||||
DEBUG_LOG("Auth not last EF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
auth_start = parsed;
|
||||
has_auth = 1;
|
||||
break;
|
||||
@@ -169,8 +179,10 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
||||
|
||||
for (parsed = 0; parsed < plaintext_length; parsed += ef_length) {
|
||||
if (!NEF_ParseSingleField(plaintext, plaintext_length, parsed,
|
||||
&ef_length, &ef_type, &ef_body, &ef_body_length))
|
||||
break;
|
||||
&ef_length, &ef_type, &ef_body, &ef_body_length)) {
|
||||
DEBUG_LOG("Could not parse encrypted EF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (ef_type) {
|
||||
case NTP_EF_NTS_COOKIE_PLACEHOLDER:
|
||||
@@ -190,13 +202,18 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prepare data for NNS_GenerateResponseAuth() to minimise the time spent
|
||||
there (when the TX timestamp is already set) */
|
||||
|
||||
UTI_GetRandomBytes(server->nonce, sizeof (server->nonce));
|
||||
|
||||
server->num_cookies = MIN(NTS_MAX_COOKIES, requested_cookies);
|
||||
for (i = 0; i < server->num_cookies; i++)
|
||||
assert(sizeof (server->cookies) / sizeof (server->cookies[0]) == NTS_MAX_COOKIES);
|
||||
for (i = 0; i < NTS_MAX_COOKIES && i < requested_cookies; i++)
|
||||
if (!NKS_GenerateCookie(&context, &server->cookies[i]))
|
||||
return 0;
|
||||
|
||||
server->num_cookies = i;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -215,14 +232,16 @@ NNS_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *req_info,
|
||||
if (!server || req_info->mode != MODE_CLIENT || res_info->mode != MODE_SERVER)
|
||||
return 0;
|
||||
|
||||
/* Make sure this is a response to the expected request */
|
||||
/* 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);
|
||||
|
||||
for (parsed = NTP_HEADER_LENGTH; parsed < req_info->length; parsed += ef_length) {
|
||||
if (!NEF_ParseField(request, req_info->length, parsed,
|
||||
&ef_length, &ef_type, &ef_body, &ef_body_length))
|
||||
break;
|
||||
/* This is not expected as the packet already passed NAU_ParsePacket() */
|
||||
return 0;
|
||||
|
||||
switch (ef_type) {
|
||||
case NTP_EF_NTS_UNIQUE_IDENTIFIER:
|
||||
@@ -240,7 +259,7 @@ NNS_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *req_info,
|
||||
|
||||
for (i = 0, plaintext_length = 0; i < server->num_cookies; i++) {
|
||||
if (!NEF_SetField(plaintext, sizeof (plaintext), plaintext_length,
|
||||
NTP_EF_NTS_COOKIE, &server->cookies[i].cookie,
|
||||
NTP_EF_NTS_COOKIE, server->cookies[i].cookie,
|
||||
server->cookies[i].length, &ef_length))
|
||||
return 0;
|
||||
|
||||
@@ -250,6 +269,8 @@ NNS_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *req_info,
|
||||
|
||||
server->num_cookies = 0;
|
||||
|
||||
/* Generate an authenticator field which will make the length
|
||||
of the response equal to the length of the request */
|
||||
if (!NNA_GenerateAuthEF(response, res_info, server->siv,
|
||||
server->nonce, sizeof (server->nonce),
|
||||
plaintext, plaintext_length,
|
||||
|
||||
18
pktlength.c
18
pktlength.c
@@ -110,8 +110,7 @@ static const struct request_length request_lengths[] = {
|
||||
REQ_LENGTH_ENTRY(smoothtime, null), /* SMOOTHTIME */
|
||||
REQ_LENGTH_ENTRY(null, null), /* REFRESH */
|
||||
REQ_LENGTH_ENTRY(null, server_stats), /* SERVER_STATS */
|
||||
REQ_LENGTH_ENTRY(client_accesses_by_index,
|
||||
client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
|
||||
{ 0, 0 }, /* CLIENT_ACCESSES_BY_INDEX2 - not supported */
|
||||
REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */
|
||||
REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */
|
||||
{ 0, 0 }, /* ADD_SERVER2 */
|
||||
@@ -123,7 +122,12 @@ static const struct request_length request_lengths[] = {
|
||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SOURCE */
|
||||
REQ_LENGTH_ENTRY(ntp_source_name,
|
||||
ntp_source_name), /* NTP_SOURCE_NAME */
|
||||
REQ_LENGTH_ENTRY(null, null), /* RESET */
|
||||
REQ_LENGTH_ENTRY(null, null), /* RESET_SOURCES */
|
||||
REQ_LENGTH_ENTRY(auth_data, auth_data), /* AUTH_DATA */
|
||||
REQ_LENGTH_ENTRY(client_accesses_by_index,
|
||||
client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX3 */
|
||||
REQ_LENGTH_ENTRY(select_data, select_data), /* SELECT_DATA */
|
||||
REQ_LENGTH_ENTRY(null, null), /* RELOAD_SOURCES */
|
||||
};
|
||||
|
||||
static const uint16_t reply_lengths[] = {
|
||||
@@ -141,12 +145,16 @@ static const uint16_t reply_lengths[] = {
|
||||
0, /* MANUAL_LIST - not supported */
|
||||
RPY_LENGTH_ENTRY(activity), /* ACTIVITY */
|
||||
RPY_LENGTH_ENTRY(smoothing), /* SMOOTHING */
|
||||
RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS */
|
||||
RPY_LENGTH_ENTRY(client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
|
||||
0, /* SERVER_STATS - not supported */
|
||||
0, /* CLIENT_ACCESSES_BY_INDEX2 - not supported */
|
||||
RPY_LENGTH_ENTRY(ntp_data), /* NTP_DATA */
|
||||
RPY_LENGTH_ENTRY(manual_timestamp), /* MANUAL_TIMESTAMP2 */
|
||||
RPY_LENGTH_ENTRY(manual_list), /* MANUAL_LIST2 */
|
||||
RPY_LENGTH_ENTRY(ntp_source_name), /* NTP_SOURCE_NAME */
|
||||
RPY_LENGTH_ENTRY(auth_data), /* AUTH_DATA */
|
||||
RPY_LENGTH_ENTRY(client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX3 */
|
||||
RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS2 */
|
||||
RPY_LENGTH_ENTRY(select_data), /* SELECT_DATA */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -253,8 +253,9 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||
inst->filter = SPF_CreateInstance(MIN(params->filter_length, 4), params->filter_length,
|
||||
params->max_dispersion, 0.6);
|
||||
|
||||
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_options, NULL,
|
||||
params->min_samples, params->max_samples, 0.0, 0.0);
|
||||
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, 0, params->sel_options,
|
||||
NULL, params->min_samples, params->max_samples,
|
||||
0.0, 0.0);
|
||||
|
||||
DEBUG_LOG("refclock %s refid=%s poll=%d dpoll=%d filter=%d",
|
||||
params->driver_name, UTI_RefidToString(inst->ref_id),
|
||||
|
||||
10
reference.c
10
reference.c
@@ -304,6 +304,8 @@ REF_Finalise(void)
|
||||
update_drift_file(LCL_ReadAbsoluteFrequency(), our_skew);
|
||||
}
|
||||
|
||||
LCL_RemoveParameterChangeHandler(handle_slew, NULL);
|
||||
|
||||
Free(fb_drifts);
|
||||
|
||||
initialised = 0;
|
||||
@@ -489,8 +491,7 @@ maybe_log_offset(double offset, time_t now)
|
||||
abs_offset = fabs(offset);
|
||||
|
||||
if (abs_offset > log_change_threshold) {
|
||||
LOG(LOGS_WARN, "System clock wrong by %.6f seconds, adjustment started",
|
||||
-offset);
|
||||
LOG(LOGS_WARN, "System clock wrong by %.6f seconds", -offset);
|
||||
}
|
||||
|
||||
if (do_mail_change &&
|
||||
@@ -556,8 +557,7 @@ is_offset_ok(double offset)
|
||||
return 1;
|
||||
}
|
||||
|
||||
offset = fabs(offset);
|
||||
if (offset > max_offset) {
|
||||
if (fabs(offset) > max_offset) {
|
||||
LOG(LOGS_WARN,
|
||||
"Adjustment of %.3f seconds exceeds the allowed maximum of %.3f seconds (%s) ",
|
||||
-offset, max_offset, !max_offset_ignore ? "exiting" : "ignored");
|
||||
@@ -1018,7 +1018,7 @@ REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
|
||||
our_residual_freq = residual_frequency;
|
||||
our_root_delay = root_delay;
|
||||
our_root_dispersion = root_dispersion;
|
||||
our_frequency_sd = offset_sd;
|
||||
our_frequency_sd = frequency_sd;
|
||||
our_offset_sd = offset_sd;
|
||||
last_ref_update = mono_now;
|
||||
last_ref_update_interval = update_interval;
|
||||
|
||||
37
reports.h
37
reports.h
@@ -37,7 +37,6 @@ typedef struct {
|
||||
int poll;
|
||||
enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode;
|
||||
enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE, RPT_OUTLIER} state;
|
||||
int sel_options;
|
||||
|
||||
int reachability;
|
||||
unsigned long latest_meas_ago; /* seconds */
|
||||
@@ -78,8 +77,8 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
struct timespec ref_time;
|
||||
unsigned short n_samples;
|
||||
unsigned short n_runs;
|
||||
unsigned long n_samples;
|
||||
unsigned long n_runs;
|
||||
unsigned long span_seconds;
|
||||
double rtc_seconds_fast;
|
||||
double rtc_gain_rate_ppm;
|
||||
@@ -88,22 +87,29 @@ typedef struct {
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
uint32_t ntp_hits;
|
||||
uint32_t nke_hits;
|
||||
uint32_t cmd_hits;
|
||||
uint16_t ntp_drops;
|
||||
uint16_t nke_drops;
|
||||
uint16_t cmd_drops;
|
||||
int8_t ntp_interval;
|
||||
int8_t nke_interval;
|
||||
int8_t cmd_interval;
|
||||
int8_t ntp_timeout_interval;
|
||||
uint32_t last_ntp_hit_ago;
|
||||
uint32_t last_nke_hit_ago;
|
||||
uint32_t last_cmd_hit_ago;
|
||||
} RPT_ClientAccessByIndex_Report;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ntp_hits;
|
||||
uint32_t nke_hits;
|
||||
uint32_t cmd_hits;
|
||||
uint32_t ntp_drops;
|
||||
uint32_t nke_drops;
|
||||
uint32_t cmd_drops;
|
||||
uint32_t log_drops;
|
||||
uint32_t ntp_auth_hits;
|
||||
} RPT_ServerStatsReport;
|
||||
|
||||
typedef struct {
|
||||
@@ -160,4 +166,29 @@ typedef struct {
|
||||
uint32_t total_valid_count;
|
||||
} RPT_NTPReport;
|
||||
|
||||
typedef struct {
|
||||
NTP_AuthMode mode;
|
||||
uint32_t key_id;
|
||||
int key_type;
|
||||
int key_length;
|
||||
int ke_attempts;
|
||||
uint32_t last_ke_ago;
|
||||
int cookies;
|
||||
int cookie_length;
|
||||
int nak;
|
||||
} RPT_AuthReport;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ref_id;
|
||||
IPAddr ip_addr;
|
||||
char state_char;
|
||||
int authentication;
|
||||
int conf_options;
|
||||
int eff_options;
|
||||
uint32_t last_sample_ago;
|
||||
double score;
|
||||
double lo_limit;
|
||||
double hi_limit;
|
||||
} RPT_SelectReport;
|
||||
|
||||
#endif /* GOT_REPORTS_H */
|
||||
|
||||
@@ -573,6 +573,10 @@ RTC_Linux_Finalise(void)
|
||||
(void) RTC_Linux_WriteParameters();
|
||||
|
||||
}
|
||||
|
||||
if (rtc_sec)
|
||||
LCL_RemoveParameterChangeHandler(slew_samples, NULL);
|
||||
|
||||
Free(rtc_sec);
|
||||
Free(rtc_trim);
|
||||
Free(system_times);
|
||||
|
||||
14
sched.c
14
sched.c
@@ -490,20 +490,6 @@ SCH_RemoveTimeout(SCH_TimeoutID id)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCH_Reset(void)
|
||||
{
|
||||
while (n_timer_queue_entries > 0)
|
||||
SCH_RemoveTimeout(timer_queue.next->id);
|
||||
|
||||
while (one_highest_fd > 0) {
|
||||
close(one_highest_fd - 1);
|
||||
SCH_RemoveFileHandler(one_highest_fd - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Try to dispatch any timeouts that have already gone by, and
|
||||
keep going until all are done. (The earlier ones may take so
|
||||
|
||||
3
sched.h
3
sched.h
@@ -85,9 +85,6 @@ extern SCH_TimeoutID SCH_AddTimeoutInClass(double min_delay, double separation,
|
||||
/* The next one probably ought to return a status code */
|
||||
extern void SCH_RemoveTimeout(SCH_TimeoutID);
|
||||
|
||||
/* Remove all timeouts and close all file descriptors */
|
||||
extern void SCH_Reset(void);
|
||||
|
||||
extern void SCH_MainLoop(void);
|
||||
|
||||
extern void SCH_QuitProgram(void);
|
||||
|
||||
250
siv_gnutls.c
Normal file
250
siv_gnutls.c
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2020
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
SIV ciphers using the GnuTLS library
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <gnutls/crypto.h>
|
||||
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "siv.h"
|
||||
|
||||
struct SIV_Instance_Record {
|
||||
gnutls_cipher_algorithm_t algorithm;
|
||||
gnutls_aead_cipher_hd_t cipher;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int instance_counter = 0;
|
||||
static int gnutls_initialised = 0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
init_gnutls(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (gnutls_initialised)
|
||||
return;
|
||||
|
||||
r = gnutls_global_init();
|
||||
if (r < 0)
|
||||
LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
|
||||
|
||||
DEBUG_LOG("Initialised");
|
||||
gnutls_initialised = 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
deinit_gnutls(void)
|
||||
{
|
||||
assert(gnutls_initialised);
|
||||
gnutls_global_deinit();
|
||||
gnutls_initialised = 0;
|
||||
DEBUG_LOG("Deinitialised");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static gnutls_cipher_algorithm_t
|
||||
get_cipher_algorithm(SIV_Algorithm algorithm)
|
||||
{
|
||||
switch (algorithm) {
|
||||
case AEAD_AES_SIV_CMAC_256:
|
||||
return GNUTLS_CIPHER_AES_128_SIV;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
SIV_Instance
|
||||
SIV_CreateInstance(SIV_Algorithm algorithm)
|
||||
{
|
||||
gnutls_cipher_algorithm_t calgo;
|
||||
SIV_Instance instance;
|
||||
|
||||
calgo = get_cipher_algorithm(algorithm);
|
||||
if (calgo == 0)
|
||||
return NULL;
|
||||
|
||||
if (instance_counter == 0)
|
||||
init_gnutls();
|
||||
|
||||
/* Check if the cipher is actually supported */
|
||||
if (gnutls_cipher_get_tag_size(calgo) == 0)
|
||||
return NULL;
|
||||
|
||||
instance = MallocNew(struct SIV_Instance_Record);
|
||||
instance->algorithm = calgo;
|
||||
instance->cipher = NULL;
|
||||
|
||||
instance_counter++;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SIV_DestroyInstance(SIV_Instance instance)
|
||||
{
|
||||
if (instance->cipher)
|
||||
gnutls_aead_cipher_deinit(instance->cipher);
|
||||
Free(instance);
|
||||
|
||||
instance_counter--;
|
||||
if (instance_counter == 0)
|
||||
deinit_gnutls();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SIV_GetKeyLength(SIV_Algorithm algorithm)
|
||||
{
|
||||
gnutls_cipher_algorithm_t calgo = get_cipher_algorithm(algorithm);
|
||||
int len;
|
||||
|
||||
if (calgo == 0)
|
||||
return 0;
|
||||
|
||||
len = gnutls_cipher_get_key_size(calgo);
|
||||
|
||||
if (len < 1 || len > SIV_MAX_KEY_LENGTH)
|
||||
LOG_FATAL("Invalid key length");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SIV_SetKey(SIV_Instance instance, const unsigned char *key, int length)
|
||||
{
|
||||
gnutls_aead_cipher_hd_t cipher;
|
||||
gnutls_datum_t datum;
|
||||
int r;
|
||||
|
||||
if (length <= 0 || length != gnutls_cipher_get_key_size(instance->algorithm))
|
||||
return 0;
|
||||
|
||||
datum.data = (unsigned char *)key;
|
||||
datum.size = length;
|
||||
|
||||
/* Initialise a new cipher with the provided key (gnutls does not seem to
|
||||
have a function to change the key directly) */
|
||||
r = gnutls_aead_cipher_init(&cipher, instance->algorithm, &datum);
|
||||
if (r < 0) {
|
||||
DEBUG_LOG("Could not initialise %s : %s", "cipher", gnutls_strerror(r));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Replace the previous cipher */
|
||||
if (instance->cipher)
|
||||
gnutls_aead_cipher_deinit(instance->cipher);
|
||||
instance->cipher = cipher;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SIV_GetTagLength(SIV_Instance instance)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = gnutls_cipher_get_tag_size(instance->algorithm);
|
||||
|
||||
if (len < 1 || len > SIV_MAX_TAG_LENGTH)
|
||||
LOG_FATAL("Invalid tag length");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SIV_Encrypt(SIV_Instance instance,
|
||||
const unsigned char *nonce, int nonce_length,
|
||||
const void *assoc, int assoc_length,
|
||||
const void *plaintext, int plaintext_length,
|
||||
unsigned char *ciphertext, int ciphertext_length)
|
||||
{
|
||||
size_t clen = ciphertext_length;
|
||||
|
||||
if (nonce_length < 1 || assoc_length < 0 ||
|
||||
plaintext_length < 0 || ciphertext_length < 0)
|
||||
return 0;
|
||||
|
||||
assert(assoc && plaintext);
|
||||
|
||||
if (gnutls_aead_cipher_encrypt(instance->cipher,
|
||||
nonce, nonce_length, assoc, assoc_length, 0,
|
||||
plaintext, plaintext_length, ciphertext, &clen) < 0)
|
||||
return 0;
|
||||
|
||||
if (clen != ciphertext_length)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SIV_Decrypt(SIV_Instance instance,
|
||||
const unsigned char *nonce, int nonce_length,
|
||||
const void *assoc, int assoc_length,
|
||||
const unsigned char *ciphertext, int ciphertext_length,
|
||||
void *plaintext, int plaintext_length)
|
||||
{
|
||||
size_t plen = plaintext_length;
|
||||
|
||||
if (nonce_length < 1 || assoc_length < 0 ||
|
||||
plaintext_length < 0 || ciphertext_length < 0)
|
||||
return 0;
|
||||
|
||||
assert(assoc && plaintext);
|
||||
|
||||
if (gnutls_aead_cipher_decrypt(instance->cipher,
|
||||
nonce, nonce_length, assoc, assoc_length, 0,
|
||||
ciphertext, ciphertext_length, plaintext, &plen) < 0)
|
||||
return 0;
|
||||
|
||||
if (plen != plaintext_length)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -69,6 +69,8 @@ SIV_DestroyInstance(SIV_Instance instance)
|
||||
int
|
||||
SIV_GetKeyLength(SIV_Algorithm algorithm)
|
||||
{
|
||||
assert(32 <= SIV_MAX_KEY_LENGTH);
|
||||
|
||||
if (algorithm == AEAD_AES_SIV_CMAC_256)
|
||||
return 32;
|
||||
return 0;
|
||||
@@ -92,6 +94,8 @@ SIV_SetKey(SIV_Instance instance, const unsigned char *key, int length)
|
||||
int
|
||||
SIV_GetTagLength(SIV_Instance instance)
|
||||
{
|
||||
assert(SIV_DIGEST_SIZE <= SIV_MAX_TAG_LENGTH);
|
||||
|
||||
return SIV_DIGEST_SIZE;
|
||||
}
|
||||
|
||||
|
||||
4
smooth.c
4
smooth.c
@@ -272,6 +272,10 @@ void SMT_Initialise(void)
|
||||
|
||||
void SMT_Finalise(void)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
LCL_RemoveParameterChangeHandler(handle_slew, NULL);
|
||||
}
|
||||
|
||||
int SMT_IsEnabled(void)
|
||||
|
||||
128
socket.c
128
socket.c
@@ -82,6 +82,10 @@ struct MessageHeader {
|
||||
|
||||
static int initialised;
|
||||
|
||||
/* Flags indicating in which IP families sockets can be requested */
|
||||
static int ip4_enabled;
|
||||
static int ip6_enabled;
|
||||
|
||||
/* Flags supported by socket() */
|
||||
static int supported_socket_flags;
|
||||
|
||||
@@ -114,7 +118,7 @@ prepare_buffers(unsigned int n)
|
||||
hdr->msg_hdr.msg_namelen = sizeof (msg->name);
|
||||
hdr->msg_hdr.msg_iov = &msg->iov;
|
||||
hdr->msg_hdr.msg_iovlen = 1;
|
||||
hdr->msg_hdr.msg_control = &msg->cmsg_buf;
|
||||
hdr->msg_hdr.msg_control = msg->cmsg_buf;
|
||||
hdr->msg_hdr.msg_controllen = sizeof (msg->cmsg_buf);
|
||||
hdr->msg_hdr.msg_flags = 0;
|
||||
hdr->msg_len = 0;
|
||||
@@ -172,7 +176,7 @@ check_socket_flag(int sock_flag, int fd_flag, int fs_flag)
|
||||
static int
|
||||
set_socket_nonblock(int sock_fd)
|
||||
{
|
||||
if (fcntl(sock_fd, F_SETFL, O_NONBLOCK)) {
|
||||
if (fcntl(sock_fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||
DEBUG_LOG("Could not set O_NONBLOCK : %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
@@ -332,6 +336,23 @@ is_any_address(IPAddr *addr)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
bind_device(int sock_fd, const char *iface)
|
||||
{
|
||||
#ifdef SO_BINDTODEVICE
|
||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface) + 1) < 0) {
|
||||
DEBUG_LOG("Could not bind socket to %s : %s", iface, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#else
|
||||
DEBUG_LOG("Could not bind socket to %s : %s", iface, "Not supported");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
bind_ip_address(int sock_fd, IPSockAddr *addr, int flags)
|
||||
{
|
||||
@@ -399,7 +420,8 @@ connect_ip_address(int sock_fd, IPSockAddr *addr)
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int type, int flags)
|
||||
open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, const char *iface,
|
||||
int type, int flags)
|
||||
{
|
||||
int domain, family, sock_fd;
|
||||
|
||||
@@ -412,10 +434,14 @@ open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int type, int fl
|
||||
|
||||
switch (family) {
|
||||
case IPADDR_INET4:
|
||||
if (!ip4_enabled)
|
||||
return INVALID_SOCK_FD;
|
||||
domain = AF_INET;
|
||||
break;
|
||||
#ifdef FEAT_IPV6
|
||||
case IPADDR_INET6:
|
||||
if (!ip6_enabled)
|
||||
return INVALID_SOCK_FD;
|
||||
domain = AF_INET6;
|
||||
break;
|
||||
#endif
|
||||
@@ -434,6 +460,9 @@ open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int type, int fl
|
||||
if (!set_ip_options(sock_fd, family, flags))
|
||||
goto error;
|
||||
|
||||
if (iface && !bind_device(sock_fd, iface))
|
||||
goto error;
|
||||
|
||||
/* Bind the socket if a non-any local address/port was specified */
|
||||
if (local_addr && local_addr->ip_addr.family != IPADDR_UNSPEC &&
|
||||
(local_addr->port != 0 || !is_any_address(&local_addr->ip_addr)) &&
|
||||
@@ -476,8 +505,8 @@ bind_unix_address(int sock_fd, const char *addr, int flags)
|
||||
}
|
||||
saddr.un.sun_family = AF_UNIX;
|
||||
|
||||
if (!UTI_RemoveFile(NULL, addr, NULL))
|
||||
;
|
||||
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) {
|
||||
@@ -627,9 +656,8 @@ log_message(int sock_fd, int direction, SCK_Message *message, const char *prefix
|
||||
case SCK_ADDR_IP:
|
||||
if (message->remote_addr.ip.ip_addr.family != IPADDR_UNSPEC)
|
||||
remote_addr = UTI_IPSockAddrToString(&message->remote_addr.ip);
|
||||
if (message->local_addr.ip.family != IPADDR_UNSPEC) {
|
||||
if (message->local_addr.ip.family != IPADDR_UNSPEC)
|
||||
local_addr = UTI_IPToString(&message->local_addr.ip);
|
||||
}
|
||||
break;
|
||||
case SCK_ADDR_UNIX:
|
||||
remote_addr = message->remote_addr.path;
|
||||
@@ -655,7 +683,7 @@ log_message(int sock_fd, int direction, SCK_Message *message, const char *prefix
|
||||
snprintf(tslen, sizeof (tslen), " tslen=%d", message->timestamp.l2_length);
|
||||
}
|
||||
|
||||
DEBUG_LOG("%s message%s%s%s%s fd=%d len=%u%s%s%s%s%s%s",
|
||||
DEBUG_LOG("%s message%s%s%s%s fd=%d len=%d%s%s%s%s%s%s",
|
||||
prefix,
|
||||
remote_addr ? (direction > 0 ? " from " : " to ") : "",
|
||||
remote_addr ? remote_addr : "",
|
||||
@@ -710,7 +738,7 @@ init_message_nonaddress(SCK_Message *message)
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_header(struct msghdr *msg, unsigned int msg_length, int sock_fd, int flags,
|
||||
process_header(struct msghdr *msg, int msg_length, int sock_fd, int flags,
|
||||
SCK_Message *message)
|
||||
{
|
||||
struct cmsghdr *cmsg;
|
||||
@@ -892,7 +920,10 @@ receive_messages(int sock_fd, int flags, int max_messages, int *num_messages)
|
||||
hdr = ARR_GetElements(recv_headers);
|
||||
n = ARR_GetSize(recv_headers);
|
||||
n = MIN(n, max_messages);
|
||||
assert(n >= 1);
|
||||
|
||||
if (n < 1 || n > MAX_RECV_MESSAGES ||
|
||||
n > ARR_GetSize(recv_messages) || n > ARR_GetSize(recv_sck_messages))
|
||||
assert(0);
|
||||
|
||||
recv_flags = get_recv_flags(flags);
|
||||
|
||||
@@ -1001,6 +1032,11 @@ send_message(int sock_fd, SCK_Message *message, int flags)
|
||||
msg.msg_namelen = 0;
|
||||
}
|
||||
|
||||
if (message->length < 0) {
|
||||
DEBUG_LOG("Invalid length %d", message->length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
iov.iov_base = message->data;
|
||||
iov.iov_len = message->length;
|
||||
msg.msg_iov = &iov;
|
||||
@@ -1094,8 +1130,15 @@ send_message(int sock_fd, SCK_Message *message, int flags)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCK_Initialise(void)
|
||||
SCK_Initialise(int family)
|
||||
{
|
||||
ip4_enabled = family == IPADDR_INET4 || family == IPADDR_UNSPEC;
|
||||
#ifdef FEAT_IPV6
|
||||
ip6_enabled = family == IPADDR_INET6 || family == IPADDR_UNSPEC;
|
||||
#else
|
||||
ip6_enabled = 0;
|
||||
#endif
|
||||
|
||||
recv_messages = ARR_CreateInstance(sizeof (struct Message));
|
||||
ARR_SetSize(recv_messages, MAX_RECV_MESSAGES);
|
||||
recv_headers = ARR_CreateInstance(sizeof (struct MessageHeader));
|
||||
@@ -1135,15 +1178,13 @@ SCK_Finalise(void)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SCK_IsFamilySupported(int family)
|
||||
SCK_IsIpFamilyEnabled(int family)
|
||||
{
|
||||
switch (family) {
|
||||
case IPADDR_INET4:
|
||||
return 1;
|
||||
return ip4_enabled;
|
||||
case IPADDR_INET6:
|
||||
#ifdef FEAT_IPV6
|
||||
return 1;
|
||||
#endif
|
||||
return ip6_enabled;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -1194,6 +1235,23 @@ SCK_GetLoopbackIPAddress(int family, IPAddr *local_addr)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SCK_IsLinkLocalIPAddress(IPAddr *addr)
|
||||
{
|
||||
switch (addr->family) {
|
||||
case IPADDR_INET4:
|
||||
/* 169.254.0.0/16 */
|
||||
return (addr->addr.in4 & 0xffff0000) == 0xa9fe0000;
|
||||
case IPADDR_INET6:
|
||||
/* fe80::/10 */
|
||||
return addr->addr.in6[0] == 0xfe && (addr->addr.in6[1] & 0xc0) == 0x80;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCK_SetPrivBind(int (*function)(int sock_fd, struct sockaddr *address,
|
||||
socklen_t address_len))
|
||||
@@ -1204,17 +1262,17 @@ SCK_SetPrivBind(int (*function)(int sock_fd, struct sockaddr *address,
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SCK_OpenUdpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int flags)
|
||||
SCK_OpenUdpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, const char *iface, int flags)
|
||||
{
|
||||
return open_ip_socket(remote_addr, local_addr, SOCK_DGRAM, flags);
|
||||
return open_ip_socket(remote_addr, local_addr, iface, SOCK_DGRAM, flags);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SCK_OpenTcpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int flags)
|
||||
SCK_OpenTcpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, const char *iface, int flags)
|
||||
{
|
||||
return open_ip_socket(remote_addr, local_addr, SOCK_STREAM, flags);
|
||||
return open_ip_socket(remote_addr, local_addr, iface, SOCK_STREAM, flags);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1353,10 +1411,15 @@ SCK_ShutdownConnection(int sock_fd)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SCK_Receive(int sock_fd, void *buffer, unsigned int length, int flags)
|
||||
SCK_Receive(int sock_fd, void *buffer, int length, int flags)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (length < 0) {
|
||||
DEBUG_LOG("Invalid length %d", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = recv(sock_fd, buffer, length, get_recv_flags(flags));
|
||||
|
||||
if (r < 0) {
|
||||
@@ -1372,16 +1435,21 @@ SCK_Receive(int sock_fd, void *buffer, unsigned int length, int flags)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SCK_Send(int sock_fd, const void *buffer, unsigned int length, int flags)
|
||||
SCK_Send(int sock_fd, const void *buffer, int length, int flags)
|
||||
{
|
||||
int r;
|
||||
|
||||
assert(flags == 0);
|
||||
|
||||
if (length < 0) {
|
||||
DEBUG_LOG("Invalid length %d", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = send(sock_fd, buffer, length, 0);
|
||||
|
||||
if (r < 0) {
|
||||
DEBUG_LOG("Could not send data fd=%d len=%u : %s", sock_fd, length, strerror(errno));
|
||||
DEBUG_LOG("Could not send data fd=%d len=%d : %s", sock_fd, length, strerror(errno));
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1444,8 +1512,10 @@ SCK_RemoveSocket(int sock_fd)
|
||||
saddr.sa.sa_family != AF_UNIX)
|
||||
return 0;
|
||||
|
||||
if (!UTI_RemoveFile(NULL, saddr.un.sun_path, NULL))
|
||||
if (unlink(saddr.un.sun_path) < 0) {
|
||||
DEBUG_LOG("Could not remove %s : %s", saddr.un.sun_path, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1468,7 +1538,7 @@ SCK_SockaddrToIPSockAddr(struct sockaddr *sa, int sa_length, IPSockAddr *ip_sa)
|
||||
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
if (sa_length < sizeof (struct sockaddr_in))
|
||||
if (sa_length < (int)sizeof (struct sockaddr_in))
|
||||
return;
|
||||
ip_sa->ip_addr.family = IPADDR_INET4;
|
||||
ip_sa->ip_addr.addr.in4 = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
|
||||
@@ -1476,7 +1546,7 @@ SCK_SockaddrToIPSockAddr(struct sockaddr *sa, int sa_length, IPSockAddr *ip_sa)
|
||||
break;
|
||||
#ifdef FEAT_IPV6
|
||||
case AF_INET6:
|
||||
if (sa_length < sizeof (struct sockaddr_in6))
|
||||
if (sa_length < (int)sizeof (struct sockaddr_in6))
|
||||
return;
|
||||
ip_sa->ip_addr.family = IPADDR_INET6;
|
||||
memcpy(&ip_sa->ip_addr.addr.in6, ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr,
|
||||
@@ -1496,7 +1566,7 @@ SCK_IPSockAddrToSockaddr(IPSockAddr *ip_sa, struct sockaddr *sa, int sa_length)
|
||||
{
|
||||
switch (ip_sa->ip_addr.family) {
|
||||
case IPADDR_INET4:
|
||||
if (sa_length < sizeof (struct sockaddr_in))
|
||||
if (sa_length < (int)sizeof (struct sockaddr_in))
|
||||
return 0;
|
||||
memset(sa, 0, sizeof (struct sockaddr_in));
|
||||
sa->sa_family = AF_INET;
|
||||
@@ -1508,7 +1578,7 @@ SCK_IPSockAddrToSockaddr(IPSockAddr *ip_sa, struct sockaddr *sa, int sa_length)
|
||||
return sizeof (struct sockaddr_in);
|
||||
#ifdef FEAT_IPV6
|
||||
case IPADDR_INET6:
|
||||
if (sa_length < sizeof (struct sockaddr_in6))
|
||||
if (sa_length < (int)sizeof (struct sockaddr_in6))
|
||||
return 0;
|
||||
memset(sa, 0, sizeof (struct sockaddr_in6));
|
||||
sa->sa_family = AF_INET6;
|
||||
@@ -1521,7 +1591,7 @@ SCK_IPSockAddrToSockaddr(IPSockAddr *ip_sa, struct sockaddr *sa, int sa_length)
|
||||
return sizeof (struct sockaddr_in6);
|
||||
#endif
|
||||
default:
|
||||
if (sa_length < sizeof (struct sockaddr))
|
||||
if (sa_length < (int)sizeof (struct sockaddr))
|
||||
return 0;
|
||||
memset(sa, 0, sizeof (struct sockaddr));
|
||||
sa->sa_family = AF_UNSPEC;
|
||||
|
||||
26
socket.h
26
socket.h
@@ -49,7 +49,7 @@ typedef enum {
|
||||
|
||||
typedef struct {
|
||||
void *data;
|
||||
unsigned int length;
|
||||
int length;
|
||||
SCK_AddressType addr_type;
|
||||
int if_index;
|
||||
|
||||
@@ -73,27 +73,33 @@ typedef struct {
|
||||
int descriptor;
|
||||
} SCK_Message;
|
||||
|
||||
/* Initialisation function */
|
||||
extern void SCK_Initialise(void);
|
||||
/* Initialisation function (the specified IP family is enabled,
|
||||
or all if IPADDR_UNSPEC) */
|
||||
extern void SCK_Initialise(int family);
|
||||
|
||||
/* Finalisation function */
|
||||
extern void SCK_Finalise(void);
|
||||
|
||||
/* Check if support for the IP family was enabled in the build */
|
||||
extern int SCK_IsFamilySupported(int family);
|
||||
/* Check if support for the IP family is enabled */
|
||||
extern int SCK_IsIpFamilyEnabled(int family);
|
||||
|
||||
/* Get the 0.0.0.0/::0 or 127.0.0.1/::1 address */
|
||||
extern void SCK_GetAnyLocalIPAddress(int family, IPAddr *local_addr);
|
||||
extern void SCK_GetLoopbackIPAddress(int family, IPAddr *local_addr);
|
||||
|
||||
/* Check if an IP address is a link-local address */
|
||||
extern int SCK_IsLinkLocalIPAddress(IPAddr *addr);
|
||||
|
||||
/* Specify a bind()-like function for binding sockets to privileged ports when
|
||||
running in a restricted process (e.g. after dropping root privileges) */
|
||||
extern void SCK_SetPrivBind(int (*function)(int sock_fd, struct sockaddr *address,
|
||||
socklen_t address_len));
|
||||
|
||||
/* Open socket */
|
||||
extern int SCK_OpenUdpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int flags);
|
||||
extern int SCK_OpenTcpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr, int flags);
|
||||
/* Open a socket (addresses and iface may be NULL) */
|
||||
extern int SCK_OpenUdpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr,
|
||||
const char *iface, int flags);
|
||||
extern int SCK_OpenTcpSocket(IPSockAddr *remote_addr, IPSockAddr *local_addr,
|
||||
const char *iface, int flags);
|
||||
extern int SCK_OpenUnixDatagramSocket(const char *remote_addr, const char *local_addr,
|
||||
int flags);
|
||||
extern int SCK_OpenUnixStreamSocket(const char *remote_addr, const char *local_addr,
|
||||
@@ -113,8 +119,8 @@ extern int SCK_AcceptConnection(int sock_fd, IPSockAddr *remote_addr);
|
||||
extern int SCK_ShutdownConnection(int sock_fd);
|
||||
|
||||
/* Receive and send data on connected sockets - recv()/send() wrappers */
|
||||
extern int SCK_Receive(int sock_fd, void *buffer, unsigned int length, int flags);
|
||||
extern int SCK_Send(int sock_fd, const void *buffer, unsigned int length, int flags);
|
||||
extern int SCK_Receive(int sock_fd, void *buffer, int length, int flags);
|
||||
extern int SCK_Send(int sock_fd, const void *buffer, int length, int flags);
|
||||
|
||||
/* Receive a single message or multiple messages. The functions return
|
||||
a pointer to static buffers, or NULL on error. The buffers are valid until
|
||||
|
||||
318
sources.c
318
sources.c
@@ -118,7 +118,13 @@ struct SRC_Instance_Record {
|
||||
/* Type of the source */
|
||||
SRC_Type type;
|
||||
|
||||
/* Options used when selecting sources */
|
||||
/* Flag indicating that the source is authenticated */
|
||||
int authenticated;
|
||||
|
||||
/* Configured selection options */
|
||||
int conf_sel_options;
|
||||
|
||||
/* Effective selection options */
|
||||
int sel_options;
|
||||
|
||||
/* Score against currently selected source */
|
||||
@@ -172,13 +178,11 @@ static double combine_limit;
|
||||
/* ================================================== */
|
||||
/* Forward prototype */
|
||||
|
||||
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);
|
||||
static char *
|
||||
source_to_string(SRC_Instance inst);
|
||||
static void update_sel_options(void);
|
||||
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);
|
||||
static char *source_to_string(SRC_Instance inst);
|
||||
|
||||
/* ================================================== */
|
||||
/* Initialisation function */
|
||||
@@ -218,9 +222,9 @@ void SRC_Finalise(void)
|
||||
/* Function to create a new instance. This would be called by one of
|
||||
the individual source-type instance creation routines. */
|
||||
|
||||
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options,
|
||||
IPAddr *addr, int min_samples, int max_samples,
|
||||
double min_delay, double asymmetry)
|
||||
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int authenticated,
|
||||
int sel_options, IPAddr *addr, int min_samples,
|
||||
int max_samples, double min_delay, double asymmetry)
|
||||
{
|
||||
SRC_Instance result;
|
||||
|
||||
@@ -253,6 +257,8 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_optio
|
||||
|
||||
result->index = n_sources;
|
||||
result->type = type;
|
||||
result->authenticated = authenticated;
|
||||
result->conf_sel_options = sel_options;
|
||||
result->sel_options = sel_options;
|
||||
result->active = 0;
|
||||
|
||||
@@ -261,6 +267,8 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_optio
|
||||
|
||||
n_sources++;
|
||||
|
||||
update_sel_options();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -285,6 +293,8 @@ void SRC_DestroyInstance(SRC_Instance instance)
|
||||
--n_sources;
|
||||
Free(instance);
|
||||
|
||||
update_sel_options();
|
||||
|
||||
/* If this was the previous reference source, we have to reselect! */
|
||||
if (selected_source_index == dead_index)
|
||||
SRC_ReselectSource();
|
||||
@@ -306,6 +316,8 @@ SRC_ResetInstance(SRC_Instance instance)
|
||||
instance->leap = LEAP_Unsynchronised;
|
||||
instance->leap_vote = 0;
|
||||
|
||||
memset(&instance->sel_info, 0, sizeof (instance->sel_info));
|
||||
|
||||
SST_ResetInstance(instance->stats);
|
||||
}
|
||||
|
||||
@@ -386,7 +398,7 @@ SRC_AccumulateSample(SRC_Instance inst, NTP_Sample *sample)
|
||||
|
||||
assert(initialised);
|
||||
|
||||
DEBUG_LOG("ip=[%s] t=%s ofs=%f del=%f disp=%f str=%d",
|
||||
DEBUG_LOG("src=%s ts=%s offset=%e delay=%e disp=%e stratum=%d",
|
||||
source_to_string(inst), UTI_TimespecToString(&sample->time), -sample->offset,
|
||||
sample->root_delay, sample->root_dispersion, sample->stratum);
|
||||
|
||||
@@ -427,7 +439,7 @@ special_mode_end(void)
|
||||
if (!sources[i]->active)
|
||||
continue;
|
||||
|
||||
/* Don't expect more updates than from an offline iburst NTP source */
|
||||
/* Don't expect more updates than the initial burst of an NTP source */
|
||||
if (sources[i]->reachability_size >= SOURCE_REACH_BITS - 1)
|
||||
continue;
|
||||
|
||||
@@ -482,6 +494,75 @@ SRC_ResetReachability(SRC_Instance inst)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
update_sel_options(void)
|
||||
{
|
||||
int options, auth_ntp_options, unauth_ntp_options, refclk_options;
|
||||
int i, auth_ntp_sources, unauth_ntp_sources;
|
||||
|
||||
auth_ntp_sources = unauth_ntp_sources = 0;
|
||||
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
if (sources[i]->conf_sel_options & SRC_SELECT_NOSELECT)
|
||||
continue;
|
||||
if (sources[i]->type != SRC_NTP)
|
||||
continue;
|
||||
if (sources[i]->authenticated)
|
||||
auth_ntp_sources++;
|
||||
else
|
||||
unauth_ntp_sources++;
|
||||
}
|
||||
|
||||
auth_ntp_options = unauth_ntp_options = refclk_options = 0;
|
||||
|
||||
/* Determine which selection options need to be added to authenticated NTP
|
||||
sources, unauthenticated NTP sources, and refclocks, to follow the
|
||||
configured selection mode */
|
||||
switch (CNF_GetAuthSelectMode()) {
|
||||
case SRC_AUTHSELECT_IGNORE:
|
||||
break;
|
||||
case SRC_AUTHSELECT_MIX:
|
||||
if (auth_ntp_sources > 0 && unauth_ntp_sources > 0)
|
||||
auth_ntp_options = refclk_options = SRC_SELECT_REQUIRE | SRC_SELECT_TRUST;
|
||||
break;
|
||||
case SRC_AUTHSELECT_PREFER:
|
||||
if (auth_ntp_sources > 0)
|
||||
unauth_ntp_options = SRC_SELECT_NOSELECT;
|
||||
break;
|
||||
case SRC_AUTHSELECT_REQUIRE:
|
||||
unauth_ntp_options = SRC_SELECT_NOSELECT;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
options = sources[i]->conf_sel_options;
|
||||
|
||||
if (options & SRC_SELECT_NOSELECT)
|
||||
continue;
|
||||
|
||||
switch (sources[i]->type) {
|
||||
case SRC_NTP:
|
||||
options |= sources[i]->authenticated ? auth_ntp_options : unauth_ntp_options;
|
||||
break;
|
||||
case SRC_REFCLOCK:
|
||||
options |= refclk_options;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (sources[i]->sel_options != options) {
|
||||
DEBUG_LOG("changing %s from %x to %x", source_to_string(sources[i]),
|
||||
(unsigned int)sources[i]->sel_options, (unsigned int)options);
|
||||
sources[i]->sel_options = options;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
log_selection_message(const char *format, const char *arg)
|
||||
{
|
||||
@@ -492,6 +573,24 @@ log_selection_message(const char *format, const char *arg)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
log_selection_source(const char *format, SRC_Instance inst)
|
||||
{
|
||||
char buf[320], *name, *ntp_name;
|
||||
|
||||
name = source_to_string(inst);
|
||||
ntp_name = inst->type == SRC_NTP ? NSR_GetName(inst->ip_addr) : NULL;
|
||||
|
||||
if (ntp_name && strcmp(name, ntp_name) != 0)
|
||||
snprintf(buf, sizeof (buf), "%s (%s)", name, ntp_name);
|
||||
else
|
||||
snprintf(buf, sizeof (buf), "%s", name);
|
||||
|
||||
log_selection_message(format, buf);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
compare_sort_elements(const void *a, const void *b)
|
||||
{
|
||||
@@ -529,6 +628,20 @@ source_to_string(SRC_Instance inst)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
mark_source(SRC_Instance inst, SRC_Status status)
|
||||
{
|
||||
inst->status = status;
|
||||
|
||||
DEBUG_LOG("%s status=%d options=%x reach=%o/%d updates=%d distant=%d leap=%d vote=%d lo=%f hi=%f",
|
||||
source_to_string(inst), (int)inst->status, (unsigned int)inst->sel_options,
|
||||
(unsigned int)inst->reachability, inst->reachability_size, inst->updates,
|
||||
inst->distant, (int)inst->leap, inst->leap_vote,
|
||||
inst->sel_info.lo_limit, inst->sel_info.hi_limit);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
mark_ok_sources(SRC_Status status)
|
||||
{
|
||||
@@ -537,7 +650,7 @@ mark_ok_sources(SRC_Status status)
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
if (sources[i]->status != SRC_OK)
|
||||
continue;
|
||||
sources[i]->status = status;
|
||||
mark_source(sources[i], status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,12 +701,12 @@ combine_sources(int n_sel_sources, struct timespec *ref_time, double *offset,
|
||||
}
|
||||
|
||||
if (sources[index]->distant) {
|
||||
sources[index]->status = SRC_DISTANT;
|
||||
mark_source(sources[index], SRC_DISTANT);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sources[index]->status == SRC_OK)
|
||||
sources[index]->status = SRC_UNSELECTED;
|
||||
mark_source(sources[index], SRC_UNSELECTED);
|
||||
|
||||
elapsed = UTI_DiffTimespecsToDouble(ref_time, &src_ref_time);
|
||||
src_offset += elapsed * src_frequency;
|
||||
@@ -642,12 +755,13 @@ 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 n_badstats_sources, max_sel_reach, max_sel_reach_size, max_badstat_reach;
|
||||
int depth, best_depth, trust_depth, best_trust_depth;
|
||||
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;
|
||||
double src_offset, src_offset_sd, src_frequency, src_frequency_sd, src_skew;
|
||||
double src_root_delay, src_root_dispersion;
|
||||
double best_lo, best_hi, distance, sel_src_distance, max_score;
|
||||
double best_trust_lo, best_trust_hi;
|
||||
double first_sample_ago, max_reach_sample_ago;
|
||||
NTP_Leap leap_status;
|
||||
|
||||
@@ -669,7 +783,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
/* Step 1 - build intervals about each source */
|
||||
|
||||
n_endpoints = 0;
|
||||
n_sel_sources = 0;
|
||||
n_sel_sources = n_sel_trust_sources = 0;
|
||||
n_badstats_sources = 0;
|
||||
sel_req_source = 0;
|
||||
max_sel_reach = max_badstat_reach = 0;
|
||||
@@ -679,6 +793,9 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
assert(sources[i]->status != SRC_OK);
|
||||
|
||||
/* Don't allow the source to vote on leap seconds unless it's selectable */
|
||||
sources[i]->leap_vote = 0;
|
||||
|
||||
/* If some sources are specified with the require option, at least one
|
||||
of them will have to be selectable in order to update the clock */
|
||||
if (sources[i]->sel_options & SRC_SELECT_REQUIRE)
|
||||
@@ -686,7 +803,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
|
||||
/* Ignore sources which were added with the noselect option */
|
||||
if (sources[i]->sel_options & SRC_SELECT_NOSELECT) {
|
||||
sources[i]->status = SRC_UNSELECTABLE;
|
||||
mark_source(sources[i], SRC_UNSELECTABLE);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -698,7 +815,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
|
||||
if (!si->select_ok) {
|
||||
++n_badstats_sources;
|
||||
sources[i]->status = SRC_BAD_STATS;
|
||||
mark_source(sources[i], SRC_BAD_STATS);
|
||||
if (max_badstat_reach < sources[i]->reachability)
|
||||
max_badstat_reach = sources[i]->reachability;
|
||||
continue;
|
||||
@@ -714,20 +831,20 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
si->hi_limit += extra_disp;
|
||||
}
|
||||
|
||||
/* Require the root distance to be below the allowed maximum */
|
||||
if (si->root_distance > max_distance) {
|
||||
sources[i]->status = SRC_BAD_DISTANCE;
|
||||
/* Require the root distance to be below the allowed maximum and the
|
||||
endpoints to be in the right order (i.e. a non-negative distance) */
|
||||
if (!(si->root_distance <= max_distance && si->lo_limit <= si->hi_limit)) {
|
||||
mark_source(sources[i], SRC_BAD_DISTANCE);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* And the same applies for the estimated standard deviation */
|
||||
if (si->std_dev > max_jitter) {
|
||||
sources[i]->status = SRC_JITTERY;
|
||||
mark_source(sources[i], SRC_JITTERY);
|
||||
continue;
|
||||
}
|
||||
|
||||
sources[i]->status = SRC_OK; /* For now */
|
||||
sources[i]->leap_vote = 0;
|
||||
|
||||
if (sources[i]->reachability && max_reach_sample_ago < first_sample_ago)
|
||||
max_reach_sample_ago = first_sample_ago;
|
||||
@@ -752,7 +869,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
can still be selected if its newest sample is not older than the oldest
|
||||
sample from reachable sources. */
|
||||
if (!sources[i]->reachability && max_reach_sample_ago < si->last_sample_ago) {
|
||||
sources[i]->status = SRC_STALE;
|
||||
mark_source(sources[i], SRC_STALE);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -774,7 +891,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
local unsychronised time and others are synchronised to it. */
|
||||
|
||||
if (si->stratum >= orphan_stratum && sources[i]->type == SRC_NTP) {
|
||||
sources[i]->status = SRC_ORPHAN;
|
||||
mark_source(sources[i], SRC_ORPHAN);
|
||||
|
||||
if (si->stratum == orphan_stratum && sources[i]->reachability &&
|
||||
(orphan_source == INVALID_SOURCE ||
|
||||
@@ -804,6 +921,9 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
if (sources[i]->status != SRC_OK)
|
||||
continue;
|
||||
|
||||
if (sources[i]->sel_options & SRC_SELECT_TRUST)
|
||||
n_sel_trust_sources++;
|
||||
|
||||
si = &sources[i]->sel_info;
|
||||
|
||||
j1 = n_endpoints;
|
||||
@@ -820,7 +940,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
n_endpoints += 2;
|
||||
}
|
||||
|
||||
DEBUG_LOG("badstat=%d sel=%d badstat_reach=%x sel_reach=%x size=%d max_reach_ago=%f",
|
||||
DEBUG_LOG("badstat=%d sel=%d badstat_reach=%o sel_reach=%o size=%d max_reach_ago=%f",
|
||||
n_badstats_sources, n_sel_sources, (unsigned int)max_badstat_reach,
|
||||
(unsigned int)max_sel_reach, max_sel_reach_size, max_reach_sample_ago);
|
||||
|
||||
@@ -876,7 +996,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
|
||||
trust_depth = best_trust_depth = 0;
|
||||
depth = best_depth = 0;
|
||||
best_lo = best_hi = 0.0;
|
||||
best_lo = best_hi = best_trust_lo = best_trust_hi = 0.0;
|
||||
|
||||
for (i = 0; i < n_endpoints; i++) {
|
||||
switch (sort_list[i].tag) {
|
||||
@@ -886,14 +1006,20 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
trust_depth++;
|
||||
if (trust_depth > best_trust_depth ||
|
||||
(trust_depth == best_trust_depth && depth > best_depth)) {
|
||||
best_trust_depth = trust_depth;
|
||||
if (trust_depth > best_trust_depth) {
|
||||
best_trust_depth = trust_depth;
|
||||
best_trust_lo = sort_list[i].offset;
|
||||
}
|
||||
best_depth = depth;
|
||||
best_lo = sort_list[i].offset;
|
||||
}
|
||||
break;
|
||||
case HIGH:
|
||||
if (trust_depth == best_trust_depth && depth == best_depth)
|
||||
best_hi = sort_list[i].offset;
|
||||
if (trust_depth == best_trust_depth) {
|
||||
if (depth == best_depth)
|
||||
best_hi = sort_list[i].offset;
|
||||
best_trust_hi = sort_list[i].offset;
|
||||
}
|
||||
if (sources[sort_list[i].index]->sel_options & SRC_SELECT_TRUST)
|
||||
trust_depth--;
|
||||
depth--;
|
||||
@@ -901,11 +1027,16 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
assert(trust_depth <= depth);
|
||||
assert(trust_depth >= 0);
|
||||
}
|
||||
|
||||
if (best_depth <= n_sel_sources / 2 && !best_trust_depth) {
|
||||
/* Could not even get half the reachable sources to agree and there
|
||||
are no trusted sources - clearly we can't synchronise */
|
||||
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)) {
|
||||
/* Could not even get half the reachable (trusted) sources to agree */
|
||||
|
||||
if (selected_source_index != INVALID_SOURCE) {
|
||||
log_selection_message("Can't synchronise: no majority", NULL);
|
||||
@@ -932,24 +1063,28 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
continue;
|
||||
|
||||
/* Check if source's interval contains the best interval, or is wholly
|
||||
contained within it. If there are any trusted sources the first
|
||||
condition is applied only to them to not allow non-trusted sources to
|
||||
move the final offset outside the interval. */
|
||||
if (((!best_trust_depth || sources[i]->sel_options & SRC_SELECT_TRUST) &&
|
||||
sources[i]->sel_info.lo_limit <= best_lo &&
|
||||
contained within it. If there are any trusted sources, other sources
|
||||
are required to be wholly contained within the best interval of the
|
||||
trusted sources to not allow non-trusted sources to move the final
|
||||
offset outside the trusted interval. */
|
||||
if ((sources[i]->sel_info.lo_limit <= best_lo &&
|
||||
sources[i]->sel_info.hi_limit >= best_hi) ||
|
||||
(sources[i]->sel_info.lo_limit >= best_lo &&
|
||||
sources[i]->sel_info.hi_limit <= best_hi)) {
|
||||
|
||||
if (!(best_trust_depth == 0 || (sources[i]->sel_options & SRC_SELECT_TRUST) ||
|
||||
(sources[i]->sel_info.lo_limit >= best_trust_lo &&
|
||||
sources[i]->sel_info.hi_limit <= best_trust_hi))) {
|
||||
mark_source(sources[i], SRC_UNTRUSTED);
|
||||
continue;
|
||||
}
|
||||
|
||||
sel_sources[n_sel_sources++] = i;
|
||||
|
||||
if (sources[i]->sel_options & SRC_SELECT_REQUIRE)
|
||||
sel_req_source = 0;
|
||||
} else if (sources[i]->sel_info.lo_limit <= best_lo &&
|
||||
sources[i]->sel_info.hi_limit >= best_hi) {
|
||||
sources[i]->status = SRC_UNTRUSTED;
|
||||
} else {
|
||||
sources[i]->status = SRC_FALSETICKER;
|
||||
mark_source(sources[i], SRC_FALSETICKER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -982,7 +1117,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
if (i < n_sel_sources) {
|
||||
for (i = j = 0; i < n_sel_sources; i++) {
|
||||
if (!(sources[sel_sources[i]]->sel_options & SRC_SELECT_PREFER))
|
||||
sources[sel_sources[i]]->status = SRC_NONPREFERRED;
|
||||
mark_source(sources[sel_sources[i]], SRC_NONPREFERRED);
|
||||
else
|
||||
sel_sources[j++] = sel_sources[i];
|
||||
}
|
||||
@@ -1046,10 +1181,8 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
sources[i]->sel_score = 1.0 / distance;
|
||||
}
|
||||
|
||||
DEBUG_LOG("select score=%f refid=%"PRIx32" match_refid=%"PRIx32" status=%u dist=%f",
|
||||
sources[i]->sel_score, sources[i]->ref_id,
|
||||
updated_inst ? updated_inst->ref_id : 0,
|
||||
sources[i]->status, distance);
|
||||
DEBUG_LOG("%s score=%f dist=%f",
|
||||
source_to_string(sources[i]), sources[i]->sel_score, distance);
|
||||
|
||||
if (max_score < sources[i]->sel_score) {
|
||||
max_score = sources[i]->sel_score;
|
||||
@@ -1070,13 +1203,11 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
if (sources[max_score_index]->updates == 0) {
|
||||
selected_source_index = INVALID_SOURCE;
|
||||
mark_ok_sources(SRC_WAITS_UPDATE);
|
||||
DEBUG_LOG("best source has no updates");
|
||||
return;
|
||||
}
|
||||
|
||||
selected_source_index = max_score_index;
|
||||
log_selection_message("Selected source %s",
|
||||
source_to_string(sources[selected_source_index]));
|
||||
log_selection_source("Selected source %s", sources[selected_source_index]);
|
||||
|
||||
/* New source has been selected, reset all scores */
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
@@ -1085,7 +1216,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
}
|
||||
}
|
||||
|
||||
sources[selected_source_index]->status = SRC_SELECTED;
|
||||
mark_source(sources[selected_source_index], SRC_SELECTED);
|
||||
|
||||
/* Don't update reference when the selected source has no new samples */
|
||||
|
||||
@@ -1095,8 +1226,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
for (i = 0; i < n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
if (sources[index]->status == SRC_OK)
|
||||
sources[index]->status = sources[index]->distant ?
|
||||
SRC_DISTANT : SRC_UNSELECTED;
|
||||
mark_source(sources[index], sources[index]->distant ? SRC_DISTANT : SRC_UNSELECTED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1196,9 +1326,8 @@ FILE *open_dumpfile(SRC_Instance inst, char mode)
|
||||
char filename[64], *dumpdir;
|
||||
|
||||
dumpdir = CNF_GetDumpDir();
|
||||
if (dumpdir[0] == '\0') {
|
||||
if (!dumpdir)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Include IP address in the name for NTP sources, or reference ID in hex */
|
||||
if (inst->type == SRC_NTP && UTI_IsIPReal(inst->ip_addr))
|
||||
@@ -1262,7 +1391,7 @@ SRC_RemoveDumpFiles(void)
|
||||
size_t i;
|
||||
|
||||
dumpdir = CNF_GetDumpDir();
|
||||
if (dumpdir[0] == '\0' ||
|
||||
if (!dumpdir ||
|
||||
snprintf(pattern, sizeof (pattern), "%s/*.dat", dumpdir) >= sizeof (pattern))
|
||||
return;
|
||||
|
||||
@@ -1389,7 +1518,6 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timespec *now)
|
||||
break;
|
||||
}
|
||||
|
||||
report->sel_options = src->sel_options;
|
||||
report->reachability = src->reachability;
|
||||
|
||||
/* Call stats module to fill out estimates */
|
||||
@@ -1423,6 +1551,78 @@ SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report, struct timespec
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static char
|
||||
get_status_char(SRC_Status status)
|
||||
{
|
||||
switch (status) {
|
||||
case SRC_UNSELECTABLE:
|
||||
return 'N';
|
||||
case SRC_BAD_STATS:
|
||||
return 'M';
|
||||
case SRC_BAD_DISTANCE:
|
||||
return 'd';
|
||||
case SRC_JITTERY:
|
||||
return '~';
|
||||
case SRC_WAITS_STATS:
|
||||
return 'w';
|
||||
case SRC_STALE:
|
||||
return 'S';
|
||||
case SRC_ORPHAN:
|
||||
return 'O';
|
||||
case SRC_UNTRUSTED:
|
||||
return 'T';
|
||||
case SRC_FALSETICKER:
|
||||
return 'x';
|
||||
case SRC_WAITS_SOURCES:
|
||||
return 'W';
|
||||
case SRC_NONPREFERRED:
|
||||
return 'P';
|
||||
case SRC_WAITS_UPDATE:
|
||||
return 'U';
|
||||
case SRC_DISTANT:
|
||||
return 'D';
|
||||
case SRC_OUTLIER:
|
||||
return 'L';
|
||||
case SRC_UNSELECTED:
|
||||
return '+';
|
||||
case SRC_SELECTED:
|
||||
return '*';
|
||||
default:
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SRC_GetSelectReport(int index, RPT_SelectReport *report)
|
||||
{
|
||||
SRC_Instance inst;
|
||||
|
||||
if (index >= n_sources || index < 0)
|
||||
return 0;
|
||||
|
||||
inst = sources[index];
|
||||
|
||||
report->ref_id = inst->ref_id;
|
||||
if (inst->ip_addr)
|
||||
report->ip_addr = *inst->ip_addr;
|
||||
else
|
||||
report->ip_addr.family = IPADDR_UNSPEC;
|
||||
report->state_char = get_status_char(inst->status);
|
||||
report->authentication = inst->authenticated;
|
||||
report->conf_options = inst->conf_sel_options;
|
||||
report->eff_options = inst->sel_options;
|
||||
report->last_sample_ago = inst->sel_info.last_sample_ago;
|
||||
report->score = inst->sel_score;
|
||||
report->lo_limit = inst->sel_info.lo_limit;
|
||||
report->hi_limit = inst->sel_info.hi_limit;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
SRC_Type
|
||||
SRC_GetType(int index)
|
||||
{
|
||||
|
||||
17
sources.h
17
sources.h
@@ -51,6 +51,14 @@ extern void SRC_Initialise(void);
|
||||
/* Finalisation function */
|
||||
extern void SRC_Finalise(void);
|
||||
|
||||
/* Modes for selecting NTP sources based on their authentication status */
|
||||
typedef enum {
|
||||
SRC_AUTHSELECT_IGNORE,
|
||||
SRC_AUTHSELECT_MIX,
|
||||
SRC_AUTHSELECT_PREFER,
|
||||
SRC_AUTHSELECT_REQUIRE,
|
||||
} SRC_AuthSelectMode;
|
||||
|
||||
typedef enum {
|
||||
SRC_NTP, /* NTP client/peer */
|
||||
SRC_REFCLOCK /* Rerefence clock */
|
||||
@@ -59,9 +67,9 @@ typedef enum {
|
||||
/* Function to create a new instance. This would be called by one of
|
||||
the individual source-type instance creation routines. */
|
||||
|
||||
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options,
|
||||
IPAddr *addr, int min_samples, int max_samples,
|
||||
double min_delay, double asymmetry);
|
||||
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int authenticated,
|
||||
int sel_options, IPAddr *addr, int min_samples,
|
||||
int max_samples, double min_delay, double asymmetry);
|
||||
|
||||
/* Function to get rid of a source when it is being unconfigured.
|
||||
This may cause the current reference source to be reselected, if this
|
||||
@@ -122,9 +130,10 @@ extern int SRC_IsSyncPeer(SRC_Instance inst);
|
||||
extern int SRC_IsReachable(SRC_Instance inst);
|
||||
extern int SRC_ReadNumberOfSources(void);
|
||||
extern int SRC_ActiveSources(void);
|
||||
extern int SRC_ReportSource(int index, RPT_SourceReport *report, struct timespec *now);
|
||||
|
||||
extern int SRC_ReportSource(int index, RPT_SourceReport *report, struct timespec *now);
|
||||
extern int SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report, struct timespec *now);
|
||||
extern int SRC_GetSelectReport(int index, RPT_SelectReport *report);
|
||||
|
||||
extern SRC_Type SRC_GetType(int index);
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ typedef struct {
|
||||
#define SRC_DEFAULT_MINSAMPLES (-1)
|
||||
#define SRC_DEFAULT_MAXSAMPLES (-1)
|
||||
#define SRC_DEFAULT_ASYMMETRY 1.0
|
||||
#define SRC_DEFAULT_NTSPORT 11443
|
||||
#define SRC_DEFAULT_NTSPORT 4460
|
||||
#define INACTIVE_AUTHKEY 0
|
||||
|
||||
/* Flags for source selection */
|
||||
|
||||
54
stubs.c
54
stubs.c
@@ -112,7 +112,7 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
|
||||
#ifndef FEAT_CMDMON
|
||||
|
||||
void
|
||||
CAM_Initialise(int family)
|
||||
CAM_Initialise(void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ MNL_Finalise(void)
|
||||
#ifndef FEAT_NTP
|
||||
|
||||
void
|
||||
NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
|
||||
NCR_AddBroadcastDestination(NTP_Remote_Address *addr, int interval)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ NCR_CheckAccessRestriction(IPAddr *ip_addr)
|
||||
}
|
||||
|
||||
void
|
||||
NIO_Initialise(int family)
|
||||
NIO_Initialise(void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -194,23 +194,30 @@ NSR_Finalise(void)
|
||||
}
|
||||
|
||||
NSR_Status
|
||||
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
|
||||
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 port, int pool, NTP_Source_Type type, SourceParameters *params)
|
||||
NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
|
||||
SourceParameters *params, uint32_t *conf_id)
|
||||
{
|
||||
return NSR_TooManySources;
|
||||
}
|
||||
|
||||
NSR_Status
|
||||
NSR_RemoveSource(NTP_Remote_Address *remote_addr)
|
||||
NSR_RemoveSource(IPAddr *address)
|
||||
{
|
||||
return NSR_NoSuchSource;
|
||||
}
|
||||
|
||||
void
|
||||
NSR_RemoveSourcesById(uint32_t conf_id)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NSR_RemoveAllSources(void)
|
||||
{
|
||||
@@ -319,6 +326,12 @@ 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)
|
||||
{
|
||||
@@ -414,12 +427,6 @@ NSD_Finalise(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
NSD_GetAuthDelay(uint32_t key_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info,
|
||||
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
|
||||
@@ -431,21 +438,20 @@ NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info,
|
||||
|
||||
#ifndef HAVE_CMAC
|
||||
|
||||
unsigned int
|
||||
CMC_GetKeyLength(const char *cipher)
|
||||
int
|
||||
CMC_GetKeyLength(CMC_Algorithm algorithm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
CMC_Instance
|
||||
CMC_CreateInstance(const char *cipher, const unsigned char *key, unsigned int length)
|
||||
CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key, int length)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
CMC_Hash(CMC_Instance inst, const unsigned char *in, unsigned int in_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
int
|
||||
CMC_Hash(CMC_Instance inst, const void *in, int in_len, unsigned char *out, int out_len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -504,14 +510,16 @@ NNC_PrepareForAuth(NNC_Instance inst)
|
||||
int
|
||||
NNC_GenerateRequestAuth(NNC_Instance inst, NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
{
|
||||
DEBUG_LOG("NTS support disabled");
|
||||
static int logged = 0;
|
||||
|
||||
LOG(logged ? LOGS_DEBUG : LOGS_WARN, "Missing NTS support");
|
||||
logged = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
{
|
||||
DEBUG_LOG("NTS support disabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -526,17 +534,17 @@ NNC_DumpData(NNC_Instance inst)
|
||||
}
|
||||
|
||||
void
|
||||
NKC_Initialise(void)
|
||||
NNC_GetReport(NNC_Instance inst, RPT_AuthReport *report)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NKC_Finalise(void)
|
||||
NKS_PreInitialise(uid_t uid, gid_t gid, int scfilter_level)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NKS_Initialise(int scfilter_level)
|
||||
NKS_Initialise(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -417,6 +417,8 @@ SYS_Generic_Finalise(void)
|
||||
|
||||
LCL_ReadRawTime(&now);
|
||||
stop_fastslew(&now);
|
||||
|
||||
LCL_RemoveParameterChangeHandler(handle_step, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
136
sys_linux.c
136
sys_linux.c
@@ -437,10 +437,13 @@ SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control)
|
||||
|
||||
UTI_DropRoot(uid, gid);
|
||||
|
||||
/* Keep CAP_NET_BIND_SERVICE only if a server NTP port can be opened
|
||||
and keep CAP_SYS_TIME only if the clock control is enabled */
|
||||
if (snprintf(cap_text, sizeof (cap_text), "%s %s",
|
||||
/* Keep CAP_NET_BIND_SERVICE if the NTP server sockets may need to be bound.
|
||||
Keep CAP_NET_RAW if an NTP socket may need to be bound to a device.
|
||||
Keep CAP_SYS_TIME if the clock control is enabled. */
|
||||
if (snprintf(cap_text, sizeof (cap_text), "%s %s %s",
|
||||
CNF_GetNTPPort() ? "cap_net_bind_service=ep" : "",
|
||||
CNF_GetBindNtpInterface() || CNF_GetBindAcquisitionInterface() ?
|
||||
"cap_net_raw=ep" : "",
|
||||
clock_control ? "cap_sys_time=ep" : "") >= sizeof (cap_text))
|
||||
assert(0);
|
||||
|
||||
@@ -478,36 +481,119 @@ SYS_Linux_EnableSystemCallFilter(int level, SYS_SystemCallContext context)
|
||||
{
|
||||
const int syscalls[] = {
|
||||
/* Clock */
|
||||
SCMP_SYS(adjtimex), SCMP_SYS(clock_adjtime), SCMP_SYS(clock_gettime),
|
||||
SCMP_SYS(gettimeofday), SCMP_SYS(settimeofday), SCMP_SYS(time),
|
||||
SCMP_SYS(adjtimex),
|
||||
SCMP_SYS(clock_adjtime),
|
||||
#ifdef __NR_clock_adjtime64
|
||||
SCMP_SYS(clock_adjtime64),
|
||||
#endif
|
||||
SCMP_SYS(clock_gettime),
|
||||
#ifdef __NR_clock_gettime64
|
||||
SCMP_SYS(clock_gettime64),
|
||||
#endif
|
||||
SCMP_SYS(gettimeofday),
|
||||
SCMP_SYS(settimeofday),
|
||||
SCMP_SYS(time),
|
||||
|
||||
/* Process */
|
||||
SCMP_SYS(clone), SCMP_SYS(exit), SCMP_SYS(exit_group), SCMP_SYS(getpid),
|
||||
SCMP_SYS(getrlimit), SCMP_SYS(getuid), SCMP_SYS(rt_sigaction), SCMP_SYS(rt_sigreturn),
|
||||
SCMP_SYS(rt_sigprocmask), SCMP_SYS(set_tid_address), SCMP_SYS(sigreturn),
|
||||
SCMP_SYS(wait4), SCMP_SYS(waitpid),
|
||||
SCMP_SYS(clone),
|
||||
SCMP_SYS(exit),
|
||||
SCMP_SYS(exit_group),
|
||||
SCMP_SYS(getpid),
|
||||
SCMP_SYS(getrlimit),
|
||||
SCMP_SYS(getuid),
|
||||
SCMP_SYS(rt_sigaction),
|
||||
SCMP_SYS(rt_sigreturn),
|
||||
SCMP_SYS(rt_sigprocmask),
|
||||
SCMP_SYS(set_tid_address),
|
||||
SCMP_SYS(sigreturn),
|
||||
SCMP_SYS(wait4),
|
||||
SCMP_SYS(waitpid),
|
||||
|
||||
/* Memory */
|
||||
SCMP_SYS(brk), SCMP_SYS(madvise), SCMP_SYS(mmap), SCMP_SYS(mmap2),
|
||||
SCMP_SYS(mprotect), SCMP_SYS(mremap), SCMP_SYS(munmap), SCMP_SYS(shmdt),
|
||||
SCMP_SYS(brk),
|
||||
SCMP_SYS(madvise),
|
||||
SCMP_SYS(mmap),
|
||||
SCMP_SYS(mmap2),
|
||||
SCMP_SYS(mprotect),
|
||||
SCMP_SYS(mremap),
|
||||
SCMP_SYS(munmap),
|
||||
SCMP_SYS(shmdt),
|
||||
|
||||
/* Filesystem */
|
||||
SCMP_SYS(_llseek), SCMP_SYS(access), SCMP_SYS(chmod), SCMP_SYS(chown),
|
||||
SCMP_SYS(chown32), SCMP_SYS(faccessat), SCMP_SYS(fchmodat), SCMP_SYS(fchownat),
|
||||
SCMP_SYS(fstat), SCMP_SYS(fstat64), SCMP_SYS(getdents), SCMP_SYS(getdents64),
|
||||
SCMP_SYS(lseek), SCMP_SYS(newfstatat), SCMP_SYS(rename), SCMP_SYS(renameat),
|
||||
SCMP_SYS(renameat2), SCMP_SYS(stat), SCMP_SYS(stat64), SCMP_SYS(statfs),
|
||||
SCMP_SYS(statfs64), SCMP_SYS(unlink), SCMP_SYS(unlinkat),
|
||||
SCMP_SYS(_llseek),
|
||||
SCMP_SYS(access),
|
||||
SCMP_SYS(chmod),
|
||||
SCMP_SYS(chown),
|
||||
SCMP_SYS(chown32),
|
||||
SCMP_SYS(faccessat),
|
||||
SCMP_SYS(fchmodat),
|
||||
SCMP_SYS(fchownat),
|
||||
SCMP_SYS(fstat),
|
||||
SCMP_SYS(fstat64),
|
||||
SCMP_SYS(getdents),
|
||||
SCMP_SYS(getdents64),
|
||||
SCMP_SYS(lseek),
|
||||
SCMP_SYS(newfstatat),
|
||||
SCMP_SYS(rename),
|
||||
SCMP_SYS(renameat),
|
||||
SCMP_SYS(renameat2),
|
||||
SCMP_SYS(stat),
|
||||
SCMP_SYS(stat64),
|
||||
SCMP_SYS(statfs),
|
||||
SCMP_SYS(statfs64),
|
||||
SCMP_SYS(unlink),
|
||||
SCMP_SYS(unlinkat),
|
||||
|
||||
/* Socket */
|
||||
SCMP_SYS(accept), SCMP_SYS(bind), SCMP_SYS(connect), SCMP_SYS(getsockname),
|
||||
SCMP_SYS(getsockopt), SCMP_SYS(recv), SCMP_SYS(recvfrom),
|
||||
SCMP_SYS(recvmmsg), SCMP_SYS(recvmsg), SCMP_SYS(send), SCMP_SYS(sendmmsg),
|
||||
SCMP_SYS(sendmsg), SCMP_SYS(sendto), SCMP_SYS(shutdown),
|
||||
SCMP_SYS(accept),
|
||||
SCMP_SYS(bind),
|
||||
SCMP_SYS(connect),
|
||||
SCMP_SYS(getsockname),
|
||||
SCMP_SYS(getsockopt),
|
||||
SCMP_SYS(recv),
|
||||
SCMP_SYS(recvfrom),
|
||||
SCMP_SYS(recvmmsg),
|
||||
#ifdef __NR_recvmmsg_time64
|
||||
SCMP_SYS(recvmmsg_time64),
|
||||
#endif
|
||||
SCMP_SYS(recvmsg),
|
||||
SCMP_SYS(send),
|
||||
SCMP_SYS(sendmmsg),
|
||||
SCMP_SYS(sendmsg),
|
||||
SCMP_SYS(sendto),
|
||||
SCMP_SYS(shutdown),
|
||||
/* TODO: check socketcall arguments */
|
||||
SCMP_SYS(socketcall),
|
||||
|
||||
/* General I/O */
|
||||
SCMP_SYS(_newselect), SCMP_SYS(close), SCMP_SYS(open), SCMP_SYS(openat), SCMP_SYS(pipe),
|
||||
SCMP_SYS(pipe2), SCMP_SYS(poll), SCMP_SYS(ppoll), SCMP_SYS(pselect6), SCMP_SYS(read),
|
||||
SCMP_SYS(futex), SCMP_SYS(select), SCMP_SYS(set_robust_list), SCMP_SYS(write),
|
||||
SCMP_SYS(_newselect),
|
||||
SCMP_SYS(close),
|
||||
SCMP_SYS(open),
|
||||
SCMP_SYS(openat),
|
||||
SCMP_SYS(pipe),
|
||||
SCMP_SYS(pipe2),
|
||||
SCMP_SYS(poll),
|
||||
SCMP_SYS(ppoll),
|
||||
#ifdef __NR_ppoll_time64
|
||||
SCMP_SYS(ppoll_time64),
|
||||
#endif
|
||||
SCMP_SYS(pselect6),
|
||||
#ifdef __NR_pselect6_time64
|
||||
SCMP_SYS(pselect6_time64),
|
||||
#endif
|
||||
SCMP_SYS(read),
|
||||
SCMP_SYS(futex),
|
||||
#ifdef __NR_futex_time64
|
||||
SCMP_SYS(futex_time64),
|
||||
#endif
|
||||
SCMP_SYS(select),
|
||||
SCMP_SYS(set_robust_list),
|
||||
SCMP_SYS(write),
|
||||
|
||||
/* Miscellaneous */
|
||||
SCMP_SYS(getrandom), SCMP_SYS(sysinfo), SCMP_SYS(uname),
|
||||
SCMP_SYS(getrandom),
|
||||
SCMP_SYS(sysinfo),
|
||||
SCMP_SYS(uname),
|
||||
};
|
||||
|
||||
const int socket_domains[] = {
|
||||
|
||||
@@ -8,12 +8,17 @@ check_config_h 'FEAT_REFCLOCK 1' || test_skip
|
||||
check_config_h 'FEAT_CMDMON 1' || test_skip
|
||||
|
||||
refclock_jitter=$jitter
|
||||
client_server_conf="
|
||||
server node1.net1.clk
|
||||
server 192.168.123.2"
|
||||
client_conf="
|
||||
refclock SHM 0 noselect
|
||||
smoothtime 400 0.001 leaponly"
|
||||
|
||||
chronyc_conf="activity
|
||||
tracking
|
||||
sourcename 192.168.123.1
|
||||
sourcename 192.168.123.2
|
||||
sources
|
||||
sourcestats
|
||||
manual list
|
||||
@@ -25,7 +30,7 @@ run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
|
||||
check_chronyc_output "^200 OK
|
||||
1 sources online
|
||||
2 sources online
|
||||
0 sources offline
|
||||
0 sources doing burst \(return to online\)
|
||||
0 sources doing burst \(return to offline\)
|
||||
@@ -43,14 +48,18 @@ Root delay : 0\.000...... seconds
|
||||
Root dispersion : 0\.000...... seconds
|
||||
Update interval : [0-9]+\.. seconds
|
||||
Leap status : Normal
|
||||
node1\.net1\.clk
|
||||
192\.168\.123\.2
|
||||
MS Name/IP address Stratum Poll Reach LastRx Last sample
|
||||
===============================================================================
|
||||
#\? SHM0 0 4 377 [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
|
||||
\^\* 192\.168\.123\.1 1 [67] 377 [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
|
||||
\^\? 192\.168\.123\.2 0 [0-9]+ 0 - \+0ns\[ \+0ns\] \+/- 0ns
|
||||
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
|
||||
==============================================================================
|
||||
SHM0 [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\.... [0-9 +-]+[un]s [0-9 ]+[un]s
|
||||
192\.168\.123\.1 [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\.... [0-9 +-]+[un]s [0-9 ]+[un]s
|
||||
192\.168\.123\.2 0 0 0 \+0\.000 2000\.000 \+0ns 4000ms
|
||||
210 n_samples = 0
|
||||
# Date Time\(UTC\) Slewed Original Residual
|
||||
=======================================================
|
||||
@@ -71,11 +80,22 @@ run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
|
||||
check_chronyc_output "^Reference ID : C0A87B01 \(node1\.net1\.clk\)" \
|
||||
|| test_fail
|
||||
|| test_fail
|
||||
|
||||
chronyc_options="-c"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
|
||||
check_chronyc_output "^C0A87B01,192\.168\.123\.1,2,12623049..\..........,-?0\.0000.....,-?0\.000......,0\.000......,(99|100)\....,-?[0-9]\....,[0-9]\....,0\.000......,0\.000......,[0-9]+\..,Normal$" \
|
||||
|| test_fail
|
||||
|
||||
chronyc_options=""
|
||||
server_strata=0
|
||||
chronyc_start=0
|
||||
client_server_conf=""
|
||||
client_conf=""
|
||||
server_conf="server 192.168.123.1"
|
||||
limit=1
|
||||
|
||||
for chronyc_conf in \
|
||||
@@ -93,10 +113,14 @@ for chronyc_conf in \
|
||||
"allow ::/0" \
|
||||
"allow" \
|
||||
"allow all 10/24" \
|
||||
"authdata" \
|
||||
"burst 5/10" \
|
||||
"burst 3/5 255.255.255.0/1.2.3.0" \
|
||||
"burst 1/2 1.2.3.0/24" \
|
||||
"clients" \
|
||||
"clients -k" \
|
||||
"clients -p 100" \
|
||||
"clients -r" \
|
||||
"cmdaccheck 1.2.3.4" \
|
||||
"cmdallow 1.2.3.4" \
|
||||
"cmdallow all 1.2.3.0/24" \
|
||||
@@ -136,9 +160,11 @@ for chronyc_conf in \
|
||||
"polltarget 1.2.3.4 10" \
|
||||
"refresh" \
|
||||
"rekey" \
|
||||
"reload sources" \
|
||||
"reselect" \
|
||||
"reselectdist 1e-3" \
|
||||
"reset" \
|
||||
"reset sources" \
|
||||
"selectdata" \
|
||||
"settime 16:30" \
|
||||
"settime 16:30:05" \
|
||||
"settime Nov 21, 2015 16:30:05" \
|
||||
@@ -151,7 +177,7 @@ for chronyc_conf in \
|
||||
do
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_chronyc_output "501 Not authorised" || test_fail
|
||||
check_chronyc_output "501 Not authorised$" || test_fail
|
||||
done
|
||||
|
||||
chronyc_conf="dns -n
|
||||
|
||||
@@ -65,4 +65,28 @@ check_packet_interval || test_fail
|
||||
check_source_selection && test_fail
|
||||
check_sync && test_fail
|
||||
|
||||
cat > tmp/keys <<-EOF
|
||||
1 MD5 HEX:1B81CBF88D4A73F2E8CE59647F6E5C1719B6CAF5
|
||||
EOF
|
||||
|
||||
server_conf="keyfile tmp/keys"
|
||||
client_server_conf="
|
||||
server 192.168.123.1 key 1
|
||||
server 192.168.123.2
|
||||
server 192.168.123.3"
|
||||
|
||||
for authselectmode in require prefer mix ignore; do
|
||||
client_conf="keyfile tmp/keys
|
||||
authselectmode $authselectmode"
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
if [ $authselectmode = ignore ]; then
|
||||
check_sync || test_fail
|
||||
else
|
||||
check_sync && test_fail
|
||||
fi
|
||||
done
|
||||
|
||||
test_pass
|
||||
|
||||
@@ -46,7 +46,7 @@ check_sync || test_fail
|
||||
|
||||
check_file_messages "20.*123\.1.* 111 111 1111" 75 80 measurements.log || test_fail
|
||||
check_file_messages "20.*123\.1.* 111 001 0000" 37 39 measurements.log || test_fail
|
||||
check_file_messages " 2 1 .* 11443 " 260 300 log.packets || test_fail
|
||||
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
|
||||
|
||||
@@ -61,7 +61,7 @@ check_sync || test_fail
|
||||
|
||||
check_file_messages "20.*123\.1.* 111 111 1111" 99 103 measurements.log || test_fail
|
||||
check_file_messages "20.*123\.1.* 111 001 0000" 0 0 measurements.log || test_fail
|
||||
check_file_messages " 2 1 .* 11443 " 350 390 log.packets || test_fail
|
||||
check_file_messages " 2 1 .* 4460 " 350 390 log.packets || test_fail
|
||||
check_file_messages "." 6 6 ntskeys || test_fail
|
||||
check_file_messages "." 11 12 192.168.123.1.nts || test_fail
|
||||
rm -f tmp/measurements.log
|
||||
@@ -80,8 +80,8 @@ check_sync || test_fail
|
||||
|
||||
check_file_messages "20.*123\.1.* 111 111 1111" 150 160 measurements.log || test_fail
|
||||
check_file_messages "20.*123\.1.* 111 001 0000" 0 0 measurements.log || test_fail
|
||||
check_file_messages " 2 1 .* 11443 " 6 10 log.packets || test_fail
|
||||
check_file_messages "^9\.......e+03 2 1 .* 11443 " 6 10 log.packets || test_fail
|
||||
check_file_messages " 2 1 .* 4460 " 6 10 log.packets || test_fail
|
||||
check_file_messages "^9\.......e+03 2 1 .* 4460 " 6 10 log.packets || test_fail
|
||||
check_file_messages "." 6 6 ntskeys || test_fail
|
||||
check_file_messages "." 11 12 192.168.123.1.nts || test_fail
|
||||
rm -f tmp/measurements.log
|
||||
@@ -95,6 +95,79 @@ check_source_selection && test_fail
|
||||
check_sync && test_fail
|
||||
|
||||
check_file_messages " 2 1 .* 123 " 0 0 log.packets || test_fail
|
||||
check_file_messages " 2 1 .* 11443 " 10 20 log.packets || test_fail
|
||||
check_file_messages " 2 1 .* 4460 " 10 20 log.packets || test_fail
|
||||
|
||||
export CLKNETSIM_START_DATE=$(date -d 'Jan 2 00:00:01 UTC 2010' +'%s')
|
||||
|
||||
client_conf="
|
||||
nosystemcert
|
||||
ntstrustedcerts tmp/server.crt"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection && test_fail
|
||||
check_sync && test_fail
|
||||
|
||||
check_file_messages " 2 1 .* 123 " 0 0 log.packets || test_fail
|
||||
check_file_messages " 2 1 .* 4460 " 10 20 log.packets || test_fail
|
||||
check_log_messages "expired certificate" 4 4 || test_fail
|
||||
|
||||
client_conf+="
|
||||
nocerttimecheck 1"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
export CLKNETSIM_START_DATE=$(date -d 'Jan 1 00:00:00 UTC 2010' +'%s')
|
||||
|
||||
server_conf="
|
||||
ntsserverkey tmp/server.key
|
||||
ntsservercert tmp/server.crt
|
||||
ntsprocesses 0
|
||||
ntsrotate 0
|
||||
ntsdumpdir tmp
|
||||
ntsntpserver 192.168.123.2"
|
||||
client_conf="
|
||||
nosystemcert
|
||||
ntstrustedcerts tmp/server.crt
|
||||
ntsrefresh 500"
|
||||
client_server_conf="server node1.net1.clk $client_server_options"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection && test_fail
|
||||
check_sync && test_fail
|
||||
|
||||
check_file_messages " 2 1 .* 4460 " 50 100 log.packets || test_fail
|
||||
check_file_messages " 2 2 .* 4460 " 0 0 log.packets || test_fail
|
||||
check_log_messages "Source 192.168.123.1 changed to 192.168.123.2" 6 8 || test_fail
|
||||
check_log_messages "Source 192.168.123.2 replaced with 192.168.123.1" 6 8 || test_fail
|
||||
|
||||
servers=2
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
check_file_messages " 3 1 .* 4460 " 100 150 log.packets || test_fail
|
||||
check_file_messages " 3 2 .* 4460 " 0 0 log.packets || test_fail
|
||||
check_log_messages "Source 192.168.123.1 changed to 192.168.123.2" 1 1 || test_fail
|
||||
check_log_messages "Source 192.168.123.2 replaced with 192.168.123.1" 0 0 || test_fail
|
||||
|
||||
server_conf+="
|
||||
ntsratelimit interval 12 burst 1 leak 4"
|
||||
|
||||
client_chronyd_options="-d -d"
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection && test_fail
|
||||
|
||||
check_file_messages " 3 1 .* 4460 1 0 2" 25 50 log.packets || test_fail
|
||||
check_file_messages " 3 2 .* 4460 " 0 0 log.packets || test_fail
|
||||
check_log_messages "Source 192.168.123.1 changed to 192.168.123.2" 2 6 || test_fail
|
||||
check_log_messages "Source 192.168.123.2 replaced with 192.168.123.1" 1 6 || test_fail
|
||||
|
||||
test_pass
|
||||
|
||||
21
test/simulation/140-noclientlog
Executable file
21
test/simulation/140-noclientlog
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
. ./test.common
|
||||
test_start "noclientlog option"
|
||||
|
||||
server_conf="noclientlog"
|
||||
client_server_options="xleave"
|
||||
client_conf="
|
||||
logdir tmp
|
||||
log rawmeasurements"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
check_file_messages "111 111 1111.* 4B " 30 200 measurements.log || test_fail
|
||||
check_file_messages "111 111 1111.* 4I " 0 0 measurements.log || test_fail
|
||||
|
||||
test_pass
|
||||
@@ -64,6 +64,7 @@ default_client_conf=""
|
||||
default_chronyc_conf=""
|
||||
default_server_chronyd_options=""
|
||||
default_client_chronyd_options=""
|
||||
default_chronyc_options=""
|
||||
|
||||
default_time_max_limit=1e-3
|
||||
default_freq_max_limit=5e-4
|
||||
@@ -276,6 +277,7 @@ check_chronyd_exit() {
|
||||
|
||||
grep -q 'chronyd exiting' tmp/log.$i && \
|
||||
! grep -q 'Adjustment.*exceeds.*exiting' tmp/log.$i && \
|
||||
! grep -q 'Assertion.*failed' tmp/log.$i && \
|
||||
test_ok || test_bad
|
||||
[ $? -eq 0 ] || ret=1
|
||||
done
|
||||
@@ -503,7 +505,7 @@ run_test() {
|
||||
|
||||
echo "node${node}_start = $chronyc_start" >> tmp/conf
|
||||
start_client $node chronyc "$chronyc_conf" "" \
|
||||
"$([ $dns -eq 0 ] && printf "%s" "-n") -h $(get_node_name $[$node - $clients])" && \
|
||||
"$([ $dns -eq 0 ] && printf "%s" "-n") -h $(get_node_name $[$node - $clients]) $chronyc_options" && \
|
||||
test_ok || test_error
|
||||
|
||||
[ $? -ne 0 ] && return 1
|
||||
|
||||
@@ -5,62 +5,150 @@
|
||||
test_start "chronyc commands"
|
||||
|
||||
start_chronyd || test_fail
|
||||
wait_for_sync || test_fail
|
||||
|
||||
for command in \
|
||||
"accheck 1.2.3.4" \
|
||||
"delete $server" \
|
||||
"add server $server" \
|
||||
"deny" \
|
||||
"allow" \
|
||||
"burst 1/1" \
|
||||
"clients" \
|
||||
"cmdallow 1.2.3.4" \
|
||||
"cmdaccheck 1.2.3.4" \
|
||||
"allow 1.2.3.4" \
|
||||
"deny 1.2.3.4" \
|
||||
"cmddeny" \
|
||||
"cmdallow" \
|
||||
"cmddeny 1.2.3.4" \
|
||||
"cmdallow 1.2.3.4" \
|
||||
"add server 127.123.1.1" \
|
||||
"delete 127.123.1.1" \
|
||||
"burst 1/1" \
|
||||
"cyclelogs" \
|
||||
"dfreq 1.0e-3" \
|
||||
"doffset -0.1" \
|
||||
"dump" \
|
||||
"local off" \
|
||||
"local" \
|
||||
"manual on" \
|
||||
"settime now" \
|
||||
"manual delete 0" \
|
||||
"settime now" \
|
||||
"manual reset" \
|
||||
"manual off" \
|
||||
"maxdelay $server 1e-2" \
|
||||
"maxdelay $server 1e-1" \
|
||||
"maxdelaydevratio $server 5.0" \
|
||||
"maxdelayratio $server 3.0" \
|
||||
"maxpoll $server 5" \
|
||||
"maxupdateskew $server 10.0" \
|
||||
"minpoll $server 3" \
|
||||
"minstratum $server 1" \
|
||||
"ntpdata $server" \
|
||||
"offline" \
|
||||
"online" \
|
||||
"onoffline" \
|
||||
"polltarget $server 10" \
|
||||
"refresh" \
|
||||
"rekey" \
|
||||
"reload sources" \
|
||||
"reselect" \
|
||||
"reselectdist 1e-3" \
|
||||
"serverstats" \
|
||||
"reset sources" \
|
||||
"smoothtime reset" \
|
||||
"smoothtime activate" \
|
||||
"shutdown" \
|
||||
; do
|
||||
run_chronyc "$command" || test_fail
|
||||
check_chronyc_output "^200 OK$" || test_fail
|
||||
done
|
||||
|
||||
run_chronyc "accheck $server" || test_fail
|
||||
check_chronyc_output "^208 Access allowed$" || test_fail
|
||||
run_chronyc "accheck 1.2.3.4" || test_fail
|
||||
check_chronyc_output "^209 Access denied$" || test_fail
|
||||
|
||||
run_chronyc "cmdaccheck 1.2.3.4" || test_fail
|
||||
check_chronyc_output "^208 Access allowed$" || test_fail
|
||||
|
||||
run_chronyc "authdata" || test_fail
|
||||
check_chronyc_output "^Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
|
||||
=========================================================================
|
||||
127\.0\.0\.1 - 0 0 0 - 0 0 0 0$" \
|
||||
|| test_chronyc
|
||||
|
||||
run_chronyc "clients" || test_fail
|
||||
check_chronyc_output "^Hostname NTP Drop Int IntL Last Cmd Drop Int Last
|
||||
===============================================================================
|
||||
127\.0\.0\.1 [1-9] 0 - - [0-9] 0 0 - -$" \
|
||||
|| test_fail
|
||||
|
||||
run_chronyc "ntpdata $server" || test_fail
|
||||
check_chronyc_output "^Remote address : 127\.0\.0\.1 \(7F000001\)
|
||||
Remote port : [0-9]+
|
||||
Local address : 127\.0\.0\.1 \(7F000001\)
|
||||
Leap status : Normal
|
||||
Version : 4
|
||||
Mode : Server
|
||||
Stratum : 10
|
||||
Poll interval : -6 \(0 seconds\)
|
||||
Precision : [0-9 +-]+ \(0\.[0-9]+ seconds\)
|
||||
Root delay : 0\.000000 seconds
|
||||
Root dispersion : 0\.000000 seconds
|
||||
Reference ID : 7F7F0101 \(\)
|
||||
Reference time : [A-Za-z0-9: ]+
|
||||
Offset : [+-]0\.......... seconds
|
||||
Peer delay : 0\.......... seconds
|
||||
Peer dispersion : 0\.......... seconds
|
||||
Response time : 0\.......... seconds
|
||||
Jitter asymmetry: \+0\.00
|
||||
NTP tests : 111 111 1110
|
||||
Interleaved : No
|
||||
Authenticated : No
|
||||
TX timestamping : (Daemon|Kernel)
|
||||
RX timestamping : (Daemon|Kernel)
|
||||
Total TX : [0-9]+
|
||||
Total RX : [0-9]+
|
||||
Total valid RX : [0-9]+$" || test_fail
|
||||
|
||||
run_chronyc "selectdata" || test_fail
|
||||
check_chronyc_output "^S Name/IP Address Auth COpts EOpts Last Score Interval +
|
||||
====================================================================
|
||||
M 127\.0\.0\.1 N ----- ----- 0 1\.0 \+0ns \+0ns$" || test_fail
|
||||
|
||||
run_chronyc "serverstats" || test_fail
|
||||
check_chronyc_output "^NTP packets received : [0-9]+
|
||||
NTP packets dropped : 0
|
||||
Command packets received : [0-9]+
|
||||
Command packets dropped : 0
|
||||
Client log records dropped : 0
|
||||
NTS-KE connections accepted: 0
|
||||
NTS-KE connections dropped : 0
|
||||
Authenticated NTP packets : 0$" || test_fail
|
||||
|
||||
run_chronyc "manual on" || test_fail
|
||||
check_chronyc_output "^200 OK$" || test_fail
|
||||
|
||||
run_chronyc "settime now" || test_fail
|
||||
check_chronyc_output "^200 OK
|
||||
Clock was.*$" || test_fail
|
||||
|
||||
run_chronyc "manual delete 0" || test_fail
|
||||
check_chronyc_output "^200 OK$" || test_fail
|
||||
|
||||
run_chronyc "settime now" || test_fail
|
||||
check_chronyc_output "^200 OK
|
||||
Clock was.*$" || test_fail
|
||||
|
||||
run_chronyc "manual list" || test_fail
|
||||
check_chronyc_output "^210 n_samples = 1
|
||||
# Date Time\(UTC\) Slewed Original Residual
|
||||
=======================================================
|
||||
0.*$" || test_fail
|
||||
|
||||
run_chronyc "manual reset" || test_fail
|
||||
check_chronyc_output "^200 OK$" || test_fail
|
||||
|
||||
run_chronyc "manual off" || test_fail
|
||||
check_chronyc_output "^200 OK$" || test_fail
|
||||
|
||||
run_chronyc "shutdown" || test_fail
|
||||
check_chronyc_output "^200 OK$" || test_fail
|
||||
|
||||
stop_chronyd || test_fail
|
||||
check_chronyd_messages || test_fail
|
||||
start_chronyd || test_fail
|
||||
|
||||
run_chronyc "makestep" && test_fail
|
||||
check_chronyc_output "500 Failure" || test_fail
|
||||
|
||||
run_chronyc "trimrtc" && test_fail
|
||||
check_chronyc_output "513 RTC driver not running" || test_fail
|
||||
|
||||
run_chronyc "writertc" && test_fail
|
||||
check_chronyc_output "513 RTC driver not running" || test_fail
|
||||
|
||||
|
||||
75
test/system/008-confload
Executable file
75
test/system/008-confload
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
test_start "loading of configuration"
|
||||
|
||||
minimal_config=1
|
||||
extra_chronyd_directives="
|
||||
include $TEST_DIR/conf1.d/conf.1
|
||||
confdir $TEST_DIR/conf1.d
|
||||
confdir $TEST_DIR/conf2.d $TEST_DIR/conf3.d $TEST_DIR/conf4.d
|
||||
sourcedir $TEST_DIR/conf5.d
|
||||
include $TEST_DIR/conf1.d/conf.2"
|
||||
|
||||
mkdir $TEST_DIR/conf{1,2,3,4,5}.d
|
||||
|
||||
echo "server 127.123.1.1" > $TEST_DIR/conf1.d/conf.1
|
||||
echo "server 127.123.1.2" > $TEST_DIR/conf1.d/conf.2
|
||||
echo "server 127.123.1.3" > $TEST_DIR/conf1.d/3.conf
|
||||
echo "server 127.123.1.4" > $TEST_DIR/conf1.d/4.conf
|
||||
echo "server 127.123.2.2" > $TEST_DIR/conf2.d/2.conf
|
||||
echo "server 127.123.2.3" > $TEST_DIR/conf2.d/3.conf
|
||||
echo "server 127.123.3.1" > $TEST_DIR/conf3.d/1.conf
|
||||
echo "server 127.123.3.2" > $TEST_DIR/conf3.d/2.conf
|
||||
echo "server 127.123.3.3" > $TEST_DIR/conf3.d/3.conf
|
||||
echo "server 127.123.4.1" > $TEST_DIR/conf4.d/1.conf
|
||||
echo "server 127.123.4.2" > $TEST_DIR/conf4.d/2.conf
|
||||
echo "server 127.123.4.3" > $TEST_DIR/conf4.d/3.conf
|
||||
echo "server 127.123.4.4" > $TEST_DIR/conf4.d/4.conf
|
||||
echo "server 127.123.5.1" > $TEST_DIR/conf5.d/1.sources
|
||||
echo "server 127.123.5.2" > $TEST_DIR/conf5.d/2.sources
|
||||
echo "server 127.123.5.3" > $TEST_DIR/conf5.d/3.sources
|
||||
|
||||
start_chronyd || test_fail
|
||||
wait_for_sync || test_fail
|
||||
|
||||
run_chronyc "sources" || test_fail
|
||||
check_chronyc_output "^[^=]*
|
||||
=*
|
||||
.. 127\.123\.1\.1 [^^]*
|
||||
.. 127\.123\.1\.3 [^^]*
|
||||
.. 127\.123\.1\.4 [^^]*
|
||||
.. 127\.123\.3\.1 [^^]*
|
||||
.. 127\.123\.2\.2 [^^]*
|
||||
.. 127\.123\.2\.3 [^^]*
|
||||
.. 127\.123\.4\.4 [^^]*
|
||||
.. 127\.123\.1\.2 [^^]*
|
||||
.. 127\.123\.5\.1 [^^]*
|
||||
.. 127\.123\.5\.2 [^^]*
|
||||
.. 127\.123\.5\.3 [^^]*$" || test_fail
|
||||
|
||||
rm $TEST_DIR/conf5.d/1.sources
|
||||
echo "server 127.123.5.2 minpoll 7" > $TEST_DIR/conf5.d/2.sources
|
||||
echo > $TEST_DIR/conf5.d/3.sources
|
||||
echo "server 127.123.5.4" > $TEST_DIR/conf5.d/4.sources
|
||||
|
||||
run_chronyc "reload sources" || test_fail
|
||||
|
||||
run_chronyc "sources" || test_fail
|
||||
check_chronyc_output "^[^=]*
|
||||
=*
|
||||
.. 127\.123\.1\.1 [^^]*
|
||||
.. 127\.123\.1\.3 [^^]*
|
||||
.. 127\.123\.1\.4 [^^]*
|
||||
.. 127\.123\.3\.1 [^^]*
|
||||
.. 127\.123\.2\.2 [^^]*
|
||||
.. 127\.123\.2\.3 [^^]*
|
||||
.. 127\.123\.4\.4 [^^]*
|
||||
.. 127\.123\.1\.2 *0 6 [^^]*
|
||||
.. 127\.123\.5\.2 *0 7 [^^]*
|
||||
.. 127\.123\.5\.4 [^^]*$" || test_fail
|
||||
|
||||
stop_chronyd || test_fail
|
||||
|
||||
test_pass
|
||||
24
test/system/009-binddevice
Executable file
24
test/system/009-binddevice
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
[ "$(uname -s)" = "Linux" ] || test_skip "non-Linux system"
|
||||
|
||||
test_start "binddevice directives"
|
||||
|
||||
extra_chronyd_directives="
|
||||
binddevice lo
|
||||
bindacqdevice lo
|
||||
bindcmddevice lo"
|
||||
|
||||
start_chronyd || test_fail
|
||||
wait_for_sync || test_fail
|
||||
|
||||
run_chronyc "ntpdata $server" || test_fail
|
||||
check_chronyc_output "^Remote address" || test_fail
|
||||
|
||||
stop_chronyd || test_fail
|
||||
check_chronyd_messages || test_fail
|
||||
check_chronyd_files || test_fail
|
||||
|
||||
test_pass
|
||||
@@ -7,7 +7,7 @@
|
||||
hwts_iface=""
|
||||
for iface_path in /sys/class/net/*; do
|
||||
iface=$(basename "$iface_path")
|
||||
if ethtool -T "$iface" 2> /dev/null | grep -q HWTSTAMP_FILTER_ALL; then
|
||||
if ethtool -T "$iface" 2> /dev/null | grep -q ' all\($\| \)'; then
|
||||
hwts_iface="$iface"
|
||||
break
|
||||
fi
|
||||
|
||||
72
test/system/105-nts
Executable file
72
test/system/105-nts
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
server_name="chrony-nts-test"
|
||||
|
||||
check_chronyd_features NTS || test_skip "NTS support disabled"
|
||||
certtool --help &> /dev/null || test_skip "certtool missing"
|
||||
sed -i "/ $server_name\$/d" /etc/hosts && echo "$server $server_name" >> /etc/hosts || \
|
||||
test_skip "Cannot modify /etc/hosts"
|
||||
|
||||
check_chronyd_features PRIVDROP && user="nobody"
|
||||
|
||||
test_start "NTS authentication"
|
||||
|
||||
cat > $TEST_DIR/cert.cfg <<EOF
|
||||
cn = "$server_name"
|
||||
serial = 001
|
||||
activation_date = "$(date -d '1 year ago' +'%Y-%m-%d') 00:00:00 UTC"
|
||||
expiration_date = "$(date -d '1 year' +'%Y-%m-%d') 00:00:00 UTC"
|
||||
signing_key
|
||||
encryption_key
|
||||
EOF
|
||||
|
||||
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.*
|
||||
|
||||
ntpport=$(get_free_port)
|
||||
ntsport=$(get_free_port)
|
||||
|
||||
server_options="port $ntpport nts ntsport $ntsport"
|
||||
extra_chronyd_directives="
|
||||
port $ntpport
|
||||
ntsport $ntsport
|
||||
ntsserverkey $TEST_DIR/server.key
|
||||
ntsservercert $TEST_DIR/server.crt
|
||||
ntstrustedcerts $TEST_DIR/server.crt
|
||||
ntsdumpdir $TEST_LIBDIR
|
||||
ntsprocesses 3"
|
||||
|
||||
start_chronyd || test_fail
|
||||
sleep 3
|
||||
|
||||
run_chronyc "authdata" || test_fail
|
||||
check_chronyc_output "^Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
|
||||
=========================================================================
|
||||
127\.0\.0\.1 NTS 1 15 256 [0-9] 0 0 [78] 100$" || test_fail
|
||||
|
||||
stop_chronyd || test_fail
|
||||
check_chronyd_messages || test_fail
|
||||
check_chronyd_files || test_fail
|
||||
|
||||
rm -f $TEST_LOGDIR/measurements.log
|
||||
|
||||
server_options="port $ntpport nts ntsport $((ntsport + 1))"
|
||||
|
||||
start_chronyd || test_fail
|
||||
sleep 2
|
||||
|
||||
run_chronyc "authdata" || test_fail
|
||||
check_chronyc_output "^Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
|
||||
=========================================================================
|
||||
127\.0\.0\.1 NTS 1 15 256 [0-9] 0 0 [78] 100$" || test_fail
|
||||
|
||||
stop_chronyd || test_fail
|
||||
check_chronyd_messages || test_fail
|
||||
check_chronyd_files || test_fail
|
||||
|
||||
test_pass
|
||||
@@ -97,6 +97,8 @@ default_extra_chronyd_directives=""
|
||||
default_extra_chronyd_options=""
|
||||
default_clock_control=0
|
||||
default_server=127.0.0.1
|
||||
default_server_name=127.0.0.1
|
||||
default_server_options=""
|
||||
default_user=root
|
||||
|
||||
# Initialize test settings from their defaults
|
||||
@@ -178,7 +180,7 @@ get_free_port() {
|
||||
|
||||
while true; do
|
||||
port=$((RANDOM % 10000 + 10000))
|
||||
netstat -aln | grep '^udp.*:'$port && continue
|
||||
netstat -aln | grep '^\(tcp\|udp\).*[:.]'"$port " && continue
|
||||
break
|
||||
done
|
||||
|
||||
@@ -210,7 +212,7 @@ generate_chrony_conf() {
|
||||
echo "cmdallow"
|
||||
echo "local"
|
||||
|
||||
echo "server $server port $ntpport minpoll -6 maxpoll -6"
|
||||
echo "server $server_name port $ntpport minpoll -6 maxpoll -6 $server_options"
|
||||
|
||||
[ "$server" = "127.0.0.1" ] && echo "bindacqaddress $server"
|
||||
echo "bindaddress 127.0.0.1"
|
||||
|
||||
@@ -12,7 +12,8 @@ TEST_OBJS := $(sort $(patsubst %.c,%.o,$(wildcard *.c)))
|
||||
TESTS := $(patsubst %.o,%.test,$(filter-out $(SHARED_OBJS),$(TEST_OBJS)))
|
||||
|
||||
CHRONYD_OBJS := $(patsubst %.o,$(CHRONY_SRCDIR)/%.o,$(filter-out main.o,\
|
||||
$(filter %.o,$(shell $(MAKE) -f $(CHRONY_SRCDIR)/Makefile print-chronyd-objects))))
|
||||
$(filter %.o,$(shell $(MAKE) -f $(CHRONY_SRCDIR)/Makefile \
|
||||
print-chronyd-objects NODEPS=1))))
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
|
||||
@@ -29,12 +29,14 @@ void
|
||||
test_unit(void)
|
||||
{
|
||||
int i, j, index;
|
||||
CLG_Service s;
|
||||
struct timespec ts;
|
||||
IPAddr ip;
|
||||
char conf[][100] = {
|
||||
"clientloglimit 10000",
|
||||
"ratelimit interval 3 burst 4 leak 3",
|
||||
"cmdratelimit interval 3 burst 4 leak 3",
|
||||
"ntsratelimit interval 6 burst 8 leak 3",
|
||||
};
|
||||
|
||||
CNF_Initialise(0, 0);
|
||||
@@ -55,15 +57,10 @@ test_unit(void)
|
||||
TST_GetRandomAddress(&ip, IPADDR_UNSPEC, i % 8 ? -1 : i / 8 % 9);
|
||||
DEBUG_LOG("address %s", UTI_IPToString(&ip));
|
||||
|
||||
if (random() % 2) {
|
||||
index = CLG_LogNTPAccess(&ip, &ts);
|
||||
TEST_CHECK(index >= 0);
|
||||
CLG_LimitNTPResponseRate(index);
|
||||
} else {
|
||||
index = CLG_LogCommandAccess(&ip, &ts);
|
||||
TEST_CHECK(index >= 0);
|
||||
CLG_LimitCommandResponseRate(index);
|
||||
}
|
||||
s = random() % MAX_SERVICES;
|
||||
index = CLG_LogServiceAccess(s, &ip, &ts);
|
||||
TEST_CHECK(index >= 0);
|
||||
CLG_LimitServiceRate(s, index);
|
||||
|
||||
UTI_AddDoubleToTimespec(&ts, (1 << random() % 14) / 100.0, &ts);
|
||||
}
|
||||
@@ -72,11 +69,13 @@ test_unit(void)
|
||||
DEBUG_LOG("records %u", ARR_GetSize(records));
|
||||
TEST_CHECK(ARR_GetSize(records) == 64);
|
||||
|
||||
s = CLG_NTP;
|
||||
|
||||
for (i = j = 0; i < 10000; i++) {
|
||||
ts.tv_sec += 1;
|
||||
index = CLG_LogNTPAccess(&ip, &ts);
|
||||
index = CLG_LogServiceAccess(s, &ip, &ts);
|
||||
TEST_CHECK(index >= 0);
|
||||
if (!CLG_LimitNTPResponseRate(index))
|
||||
if (!CLG_LimitServiceRate(s, index))
|
||||
j++;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <sysincl.h>
|
||||
#include <cmac.h>
|
||||
#include <logging.h>
|
||||
#include <util.h>
|
||||
#include "test.h"
|
||||
|
||||
#define MAX_KEY_LENGTH 64
|
||||
@@ -30,9 +31,9 @@
|
||||
struct cmac_test {
|
||||
const char *name;
|
||||
const unsigned char key[MAX_KEY_LENGTH];
|
||||
unsigned int key_length;
|
||||
int key_length;
|
||||
const unsigned char hash[MAX_HASH_LENGTH];
|
||||
unsigned int hash_length;
|
||||
int hash_length;
|
||||
};
|
||||
|
||||
void
|
||||
@@ -49,29 +50,36 @@ test_unit(void)
|
||||
{ "", "", 0, "", 0 }
|
||||
};
|
||||
|
||||
CMC_Algorithm algorithm;
|
||||
CMC_Instance inst;
|
||||
unsigned int length;
|
||||
int i, j;
|
||||
int i, j, length;
|
||||
|
||||
#ifndef HAVE_CMAC
|
||||
TEST_REQUIRE(0);
|
||||
#endif
|
||||
|
||||
TEST_CHECK(CMC_INVALID == 0);
|
||||
|
||||
for (i = 0; tests[i].name[0] != '\0'; i++) {
|
||||
TEST_CHECK(CMC_GetKeyLength(tests[i].name) == tests[i].key_length);
|
||||
algorithm = UTI_CmacNameToAlgorithm(tests[i].name);
|
||||
TEST_CHECK(algorithm != 0);
|
||||
TEST_CHECK(CMC_GetKeyLength(algorithm) == tests[i].key_length);
|
||||
|
||||
DEBUG_LOG("testing %s", tests[i].name);
|
||||
|
||||
for (j = 0; j <= 128; j++) {
|
||||
for (j = -1; j <= 128; j++) {
|
||||
if (j == tests[i].key_length)
|
||||
continue;
|
||||
TEST_CHECK(!CMC_CreateInstance(tests[i].name, tests[i].key, j));
|
||||
TEST_CHECK(!CMC_CreateInstance(algorithm, tests[i].key, j));
|
||||
}
|
||||
|
||||
inst = CMC_CreateInstance(tests[i].name, tests[i].key, tests[i].key_length);
|
||||
inst = CMC_CreateInstance(algorithm, tests[i].key, tests[i].key_length);
|
||||
TEST_CHECK(inst);
|
||||
|
||||
TEST_CHECK(!CMC_CreateInstance("nosuchcipher", tests[i].key, tests[i].key_length));
|
||||
TEST_CHECK(!CMC_CreateInstance(0, tests[i].key, tests[i].key_length));
|
||||
|
||||
TEST_CHECK(CMC_Hash(inst, data, -1, hash, sizeof (hash)) == 0);
|
||||
TEST_CHECK(CMC_Hash(inst, data, sizeof (data) - 1, hash, -1) == 0);
|
||||
|
||||
for (j = 0; j <= sizeof (hash); j++) {
|
||||
memset(hash, 0, sizeof (hash));
|
||||
|
||||
@@ -22,12 +22,13 @@
|
||||
#include <sysincl.h>
|
||||
#include <hash.h>
|
||||
#include <logging.h>
|
||||
#include <util.h>
|
||||
#include "test.h"
|
||||
|
||||
struct hash_test {
|
||||
const char *name;
|
||||
const unsigned char out[MAX_HASH_LENGTH];
|
||||
unsigned int length;
|
||||
int length;
|
||||
};
|
||||
|
||||
void
|
||||
@@ -69,27 +70,35 @@ test_unit(void)
|
||||
{ "", "", 0 }
|
||||
};
|
||||
|
||||
unsigned int length;
|
||||
int i, j, hash_id;
|
||||
HSH_Algorithm algorithm;
|
||||
int i, j, hash_id, length;
|
||||
|
||||
TEST_CHECK(HSH_INVALID == 0);
|
||||
|
||||
for (i = 0; tests[i].name[0] != '\0'; i++) {
|
||||
hash_id = HSH_GetHashId(tests[i].name);
|
||||
algorithm = UTI_HashNameToAlgorithm(tests[i].name);
|
||||
TEST_CHECK(algorithm != 0);
|
||||
hash_id = HSH_GetHashId(algorithm);
|
||||
if (hash_id < 0) {
|
||||
TEST_CHECK(strcmp(tests[i].name, "MD5"));
|
||||
TEST_CHECK(algorithm != HSH_MD5);
|
||||
#ifdef FEAT_SECHASH
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA1"));
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA256"));
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA384"));
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA512"));
|
||||
TEST_CHECK(algorithm != HSH_SHA1);
|
||||
TEST_CHECK(algorithm != HSH_SHA256);
|
||||
TEST_CHECK(algorithm != HSH_SHA384);
|
||||
TEST_CHECK(algorithm != HSH_SHA512);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_LOG("testing %s", tests[i].name);
|
||||
|
||||
TEST_CHECK(HSH_Hash(hash_id, data1, -1, NULL, 0, out, sizeof (out)) == 0);
|
||||
TEST_CHECK(HSH_Hash(hash_id, data1, sizeof (data1) - 1, data2, -1, out, sizeof (out)) == 0);
|
||||
TEST_CHECK(HSH_Hash(hash_id, data1, sizeof (data1) - 1, NULL, 0, out, -1) == 0);
|
||||
|
||||
for (j = 0; j <= sizeof (out); j++) {
|
||||
TEST_CHECK(HSH_GetHashId(tests[i].name) == hash_id);
|
||||
TEST_CHECK(HSH_GetHashId("nosuchhash") < 0);
|
||||
TEST_CHECK(HSH_GetHashId(algorithm) == hash_id);
|
||||
TEST_CHECK(HSH_GetHashId(0) < 0);
|
||||
|
||||
memset(out, 0, sizeof (out));
|
||||
length = HSH_Hash(hash_id, data1, sizeof (data1) - 1, data2, sizeof (data2) - 1,
|
||||
|
||||
@@ -99,7 +99,7 @@ generate_key_file(const char *name, uint32_t *keys)
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
int i, j, data_len, auth_len;
|
||||
int i, j, data_len, auth_len, type, bits;
|
||||
uint32_t keys[KEYS], key;
|
||||
unsigned char data[100], auth[MAX_HASH_LENGTH];
|
||||
char conf[][100] = {
|
||||
@@ -125,7 +125,6 @@ test_unit(void)
|
||||
|
||||
for (j = 0; j < KEYS; j++) {
|
||||
TEST_CHECK(KEY_KeyKnown(keys[j]));
|
||||
TEST_CHECK(KEY_GetAuthDelay(keys[j]) >= 0);
|
||||
TEST_CHECK(KEY_GetAuthLength(keys[j]) >= 16);
|
||||
|
||||
data_len = random() % (sizeof (data) + 1);
|
||||
@@ -144,12 +143,16 @@ test_unit(void)
|
||||
|
||||
auth[auth_len - 1]++;
|
||||
TEST_CHECK(!KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
|
||||
|
||||
TEST_CHECK(KEY_GetKeyInfo(keys[j], &type, &bits));
|
||||
TEST_CHECK(type > 0 && bits > 0);
|
||||
}
|
||||
|
||||
for (j = 0; j < 1000; j++) {
|
||||
UTI_GetRandomBytes(&key, sizeof (key));
|
||||
if (KEY_KeyKnown(key))
|
||||
continue;
|
||||
TEST_CHECK(!KEY_GetKeyInfo(key, &type, &bits));
|
||||
TEST_CHECK(!KEY_GenerateAuth(key, data, data_len, auth, sizeof (auth)));
|
||||
TEST_CHECK(!KEY_CheckAuth(key, data, data_len, auth, auth_len, auth_len));
|
||||
}
|
||||
|
||||
@@ -137,8 +137,8 @@ static void
|
||||
send_response(int interleaved, int authenticated, int allow_update, int valid_ts, int valid_auth)
|
||||
{
|
||||
NTP_Packet *req, *res;
|
||||
uint32_t key_id = 0;
|
||||
int auth_len = 0;
|
||||
uint32_t key_id;
|
||||
|
||||
req = &req_buffer;
|
||||
res = &res_buffer;
|
||||
@@ -322,7 +322,7 @@ test_unit(void)
|
||||
TST_RegisterDummyDrivers();
|
||||
SCH_Initialise();
|
||||
SRC_Initialise();
|
||||
NIO_Initialise(IPADDR_UNSPEC);
|
||||
NIO_Initialise();
|
||||
NCR_Initialise();
|
||||
REF_Initialise();
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ test_unit(void)
|
||||
LCL_Initialise();
|
||||
SCH_Initialise();
|
||||
SRC_Initialise();
|
||||
NIO_Initialise(IPADDR_UNSPEC);
|
||||
NIO_Initialise();
|
||||
NCR_Initialise();
|
||||
NSR_Initialise();
|
||||
|
||||
@@ -66,16 +66,16 @@ test_unit(void)
|
||||
DEBUG_LOG("adding source %s hash %"PRIu32, UTI_IPToString(&addrs[j].ip_addr),
|
||||
UTI_IPToHash(&addrs[j].ip_addr) % (1U << i));
|
||||
|
||||
NSR_AddSource(&addrs[j], random() % 2 ? NTP_SERVER : NTP_PEER, ¶ms);
|
||||
NSR_AddSource(&addrs[j], random() % 2 ? NTP_SERVER : NTP_PEER, ¶ms, NULL);
|
||||
|
||||
for (k = 0; k < j; k++) {
|
||||
addr = addrs[k];
|
||||
find_slot(&addr, &slot, &found);
|
||||
found = find_slot2(&addr, &slot);
|
||||
TEST_CHECK(found == 2);
|
||||
TEST_CHECK(!UTI_CompareIPs(&get_record(slot)->remote_addr->ip_addr,
|
||||
&addr.ip_addr, NULL));
|
||||
addr.port++;
|
||||
find_slot(&addr, &slot, &found);
|
||||
found = find_slot2(&addr, &slot);
|
||||
TEST_CHECK(found == 1);
|
||||
TEST_CHECK(!UTI_CompareIPs(&get_record(slot)->remote_addr->ip_addr,
|
||||
&addr.ip_addr, NULL));
|
||||
@@ -84,10 +84,10 @@ test_unit(void)
|
||||
|
||||
for (j = 0; j < sizeof (addrs) / sizeof (addrs[0]); j++) {
|
||||
DEBUG_LOG("removing source %s", UTI_IPToString(&addrs[j].ip_addr));
|
||||
NSR_RemoveSource(&addrs[j]);
|
||||
NSR_RemoveSource(&addrs[j].ip_addr);
|
||||
|
||||
for (k = 0; k < sizeof (addrs) / sizeof (addrs[0]); k++) {
|
||||
find_slot(&addrs[k], &slot, &found);
|
||||
found = find_slot2(&addrs[k], &slot);
|
||||
TEST_CHECK(found == (k <= j ? 0 : 2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ prepare_response(NKSN_Instance session, int valid)
|
||||
if (valid)
|
||||
index = -1;
|
||||
else
|
||||
index = random() % 9;
|
||||
index = random() % 10;
|
||||
DEBUG_LOG("index=%d", index);
|
||||
|
||||
NKSN_BeginMessage(session);
|
||||
@@ -89,8 +89,12 @@ prepare_response(NKSN_Instance session, int valid)
|
||||
}
|
||||
|
||||
if (index != 8) {
|
||||
for (i = 0; i < NKE_MAX_COOKIES; i++)
|
||||
for (i = 0; i < NKE_MAX_COOKIES; i++) {
|
||||
length = (random() % sizeof (data) + 1) / 4 * 4;
|
||||
if (index == 9)
|
||||
length += (length < sizeof (data) ? 1 : -1) * (random() % 3 + 1);
|
||||
TEST_CHECK(NKSN_AddRecord(session, 0, NKE_RECORD_COOKIE, data, length));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CHECK(NKSN_EndMessage(session));
|
||||
@@ -112,7 +116,6 @@ test_unit(void)
|
||||
CNF_ParseLine(NULL, i + 1, conf[i]);
|
||||
|
||||
LCL_Initialise();
|
||||
NKC_Initialise();
|
||||
|
||||
SCK_GetLoopbackIPAddress(AF_INET, &addr.ip_addr);
|
||||
addr.port = 0;
|
||||
@@ -129,7 +132,6 @@ test_unit(void)
|
||||
|
||||
NKC_DestroyInstance(inst);
|
||||
|
||||
NKC_Finalise();
|
||||
LCL_Finalise();
|
||||
CNF_Finalise();
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ prepare_request(NKSN_Instance session, int valid)
|
||||
if (valid)
|
||||
index = -1;
|
||||
else
|
||||
index = random() % 7;
|
||||
index = random() % 9;
|
||||
DEBUG_LOG("index=%d", index);
|
||||
|
||||
NKSN_BeginMessage(session);
|
||||
@@ -61,30 +61,34 @@ prepare_request(NKSN_Instance session, int valid)
|
||||
|
||||
if (index != 0) {
|
||||
memset(data, NKE_NEXT_PROTOCOL_NTPV4 + 1, sizeof (data));
|
||||
data[0] = htons(NKE_NEXT_PROTOCOL_NTPV4);
|
||||
if (index == 1)
|
||||
data[0] = htons(NKE_NEXT_PROTOCOL_NTPV4 + random() % 10 + 1);
|
||||
else
|
||||
data[0] = htons(NKE_NEXT_PROTOCOL_NTPV4);
|
||||
if (index == 2)
|
||||
length = 0;
|
||||
else if (index == 2)
|
||||
length = 3 + random() % 15 * 2;
|
||||
else
|
||||
length = 2 + random() % 16 * 2;
|
||||
TEST_CHECK(NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, data, length));
|
||||
}
|
||||
|
||||
if (index != 3) {
|
||||
if (index == 4)
|
||||
data[0] = htons(AEAD_AES_SIV_CMAC_256 + random() % 10 + 1);
|
||||
else
|
||||
data[0] = htons(AEAD_AES_SIV_CMAC_256);
|
||||
if (index == 3)
|
||||
TEST_CHECK(NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, data, length));
|
||||
|
||||
if (index != 4) {
|
||||
data[0] = htons(AEAD_AES_SIV_CMAC_256);
|
||||
if (index == 5)
|
||||
length = 0;
|
||||
else if (index == 6)
|
||||
length = 3 + random() % 15 * 2;
|
||||
else
|
||||
length = 2 + random() % 16 * 2;
|
||||
TEST_CHECK(NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, data, length));
|
||||
}
|
||||
|
||||
if (index == 6) {
|
||||
if (index == 7)
|
||||
TEST_CHECK(NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, data, length));
|
||||
|
||||
if (index == 8) {
|
||||
length = random() % (sizeof (data) + 1);
|
||||
TEST_CHECK(NKSN_AddRecord(session, 1, 1000 + random() % 1000, data, length));
|
||||
}
|
||||
@@ -154,7 +158,8 @@ test_unit(void)
|
||||
SCH_Initialise();
|
||||
|
||||
unlink("ntskeys");
|
||||
NKS_Initialise(0);
|
||||
NKS_PreInitialise(0, 0, 0);
|
||||
NKS_Initialise();
|
||||
|
||||
session = NKSN_CreateInstance(1, NULL, handle_message, NULL);
|
||||
|
||||
|
||||
@@ -53,22 +53,34 @@ send_message(NKSN_Instance inst)
|
||||
|
||||
NKSN_BeginMessage(inst);
|
||||
|
||||
TEST_CHECK(check_message_format(&inst->message, 0));
|
||||
TEST_CHECK(!check_message_format(&inst->message, 1));
|
||||
|
||||
TEST_CHECK(!NKSN_AddRecord(inst, 0, 1, record, NKE_MAX_MESSAGE_LENGTH - 4 + 1));
|
||||
|
||||
TEST_CHECK(check_message_format(&inst->message, 0));
|
||||
TEST_CHECK(!check_message_format(&inst->message, 1));
|
||||
|
||||
for (i = 0; i < records; i++) {
|
||||
TEST_CHECK(NKSN_AddRecord(inst, critical, type_start + i, record, record_length));
|
||||
TEST_CHECK(!NKSN_AddRecord(inst, 0, 1, &record,
|
||||
NKE_MAX_MESSAGE_LENGTH - inst->message.length - 4 + 1));
|
||||
|
||||
TEST_CHECK(check_message_format(&inst->message, 0));
|
||||
TEST_CHECK(!check_message_format(&inst->message, 1));
|
||||
}
|
||||
|
||||
TEST_CHECK(NKSN_EndMessage(inst));
|
||||
|
||||
TEST_CHECK(check_message_format(&inst->message, 0));
|
||||
TEST_CHECK(check_message_format(&inst->message, 1));
|
||||
}
|
||||
|
||||
static void
|
||||
verify_message(NKSN_Instance inst)
|
||||
{
|
||||
unsigned char buffer[NKE_MAX_MESSAGE_LENGTH];
|
||||
int i, c, t, length, buffer_length;
|
||||
int i, c, t, length, buffer_length, msg_length, prev_parsed;
|
||||
NKE_Key c2s, s2c;
|
||||
|
||||
for (i = 0; i < records; i++) {
|
||||
@@ -76,6 +88,9 @@ verify_message(NKSN_Instance inst)
|
||||
buffer_length = random() % (record_length + 1);
|
||||
assert(buffer_length <= sizeof (buffer));
|
||||
|
||||
prev_parsed = inst->message.parsed;
|
||||
msg_length = inst->message.length;
|
||||
|
||||
TEST_CHECK(NKSN_GetRecord(inst, &c, &t, &length, buffer, buffer_length));
|
||||
TEST_CHECK(c == critical);
|
||||
TEST_CHECK(t == type_start + i);
|
||||
@@ -83,6 +98,20 @@ verify_message(NKSN_Instance inst)
|
||||
TEST_CHECK(memcmp(record, buffer, buffer_length) == 0);
|
||||
if (buffer_length < record_length)
|
||||
TEST_CHECK(buffer[buffer_length] == 0);
|
||||
|
||||
inst->message.length = inst->message.parsed - 1;
|
||||
inst->message.parsed = prev_parsed;
|
||||
TEST_CHECK(!get_record(&inst->message, NULL, NULL, NULL, buffer, buffer_length));
|
||||
TEST_CHECK(inst->message.parsed == prev_parsed);
|
||||
inst->message.length = msg_length;
|
||||
if (msg_length < 0x8000) {
|
||||
inst->message.data[prev_parsed + 2] ^= 0x80;
|
||||
TEST_CHECK(!get_record(&inst->message, NULL, NULL, NULL, buffer, buffer_length));
|
||||
TEST_CHECK(inst->message.parsed == prev_parsed);
|
||||
inst->message.data[prev_parsed + 2] ^= 0x80;
|
||||
}
|
||||
TEST_CHECK(get_record(&inst->message, NULL, NULL, NULL, buffer, buffer_length));
|
||||
TEST_CHECK(inst->message.parsed > prev_parsed);
|
||||
}
|
||||
|
||||
TEST_CHECK(!NKSN_GetRecord(inst, &critical, &t, &length, buffer, sizeof (buffer)));
|
||||
|
||||
@@ -82,6 +82,10 @@ test_unit(void)
|
||||
TEST_CHECK(r);
|
||||
TEST_CHECK(info.length - packet_length >= min_ef_length);
|
||||
|
||||
r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
|
||||
-1, &plaintext2_length);
|
||||
TEST_CHECK(!r);
|
||||
|
||||
r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
|
||||
sizeof (plaintext2), &plaintext2_length);
|
||||
TEST_CHECK(r);
|
||||
|
||||
@@ -27,10 +27,11 @@
|
||||
#include "ntp.h"
|
||||
#include "nts_ke_client.h"
|
||||
|
||||
#define NKC_CreateInstance(address, name) NULL
|
||||
#define NKC_DestroyInstance(inst)
|
||||
#define NKC_CreateInstance(address, name) Malloc(1)
|
||||
#define NKC_DestroyInstance(inst) Free(inst)
|
||||
#define NKC_Start(inst) (random() % 2)
|
||||
#define NKC_IsActive(inst) (random() % 2)
|
||||
#define NKC_GetRetryFactor(inst) (1)
|
||||
|
||||
static int get_nts_data(NKC_Instance inst, NKE_Context *context,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
|
||||
@@ -59,6 +60,8 @@ get_nts_data(NKC_Instance inst, NKE_Context *context,
|
||||
*num_cookies = random() % max_cookies + 1;
|
||||
for (i = 0; i < *num_cookies; i++) {
|
||||
cookies[i].length = random() % (sizeof (cookies[i].cookie) + 1);
|
||||
if (random() % 4 != 0)
|
||||
cookies[i].length = cookies[i].length / 4 * 4;
|
||||
memset(cookies[i].cookie, random(), cookies[i].length);
|
||||
}
|
||||
|
||||
@@ -81,10 +84,14 @@ get_request(NNC_Instance inst)
|
||||
info.version = 4;
|
||||
info.mode = MODE_CLIENT;
|
||||
info.length = random() % (sizeof (packet) + 1);
|
||||
if (random() % 4 != 0)
|
||||
info.length = info.length / 4 * 4;
|
||||
|
||||
inst->num_cookies = 0;
|
||||
if (inst->num_cookies > 0 && random() % 2) {
|
||||
inst->num_cookies = 0;
|
||||
|
||||
TEST_CHECK(!NNC_GenerateRequestAuth(inst, &packet, &info));
|
||||
TEST_CHECK(!NNC_GenerateRequestAuth(inst, &packet, &info));
|
||||
}
|
||||
|
||||
while (!NNC_PrepareForAuth(inst)) {
|
||||
inst->next_nke_attempt = SCH_GetLastEventMonoTime() + random() % 10 - 7;
|
||||
@@ -124,9 +131,9 @@ get_request(NNC_Instance inst)
|
||||
static void
|
||||
prepare_response(NNC_Instance inst, NTP_Packet *packet, NTP_PacketInfo *info, int valid, int nak)
|
||||
{
|
||||
unsigned char cookie[508], plaintext[512], nonce[512];
|
||||
int nonce_length, cookie_length, plaintext_length, min_auth_length;
|
||||
int index, auth_start;
|
||||
unsigned char cookie[508], plaintext[528], nonce[448];
|
||||
int nonce_length, ef_length, cookie_length, plaintext_length, min_auth_length;
|
||||
int i, index, auth_start;
|
||||
SIV_Instance siv;
|
||||
|
||||
memset(packet, 0, sizeof (*packet));
|
||||
@@ -139,7 +146,7 @@ prepare_response(NNC_Instance inst, NTP_Packet *packet, NTP_PacketInfo *info, in
|
||||
if (valid)
|
||||
index = -1;
|
||||
else
|
||||
index = random() % (nak ? 2 : 6);
|
||||
index = random() % (nak ? 2 : 8);
|
||||
|
||||
DEBUG_LOG("index=%d nak=%d", index, nak);
|
||||
|
||||
@@ -168,16 +175,29 @@ prepare_response(NNC_Instance inst, NTP_Packet *packet, NTP_PacketInfo *info, in
|
||||
DEBUG_LOG("nonce_length=%d cookie_length=%d min_auth_length=%d",
|
||||
nonce_length, cookie_length, min_auth_length);
|
||||
|
||||
|
||||
UTI_GetRandomBytes(nonce, nonce_length);
|
||||
UTI_GetRandomBytes(cookie, cookie_length);
|
||||
|
||||
if (cookie_length >= 12 && cookie_length <= 32 && random() % 2 == 0)
|
||||
TEST_CHECK(NEF_AddField(packet, info, NTP_EF_NTS_COOKIE, cookie, cookie_length));
|
||||
|
||||
plaintext_length = 0;
|
||||
if (index != 3)
|
||||
TEST_CHECK(NEF_SetField(plaintext, sizeof (plaintext), 0, NTP_EF_NTS_COOKIE,
|
||||
cookie, cookie_length, &plaintext_length));
|
||||
if (index != 3) {
|
||||
for (i = random() % ((sizeof (plaintext) - 16) / (cookie_length + 4)); i >= 0; i--) {
|
||||
TEST_CHECK(NEF_SetField(plaintext, sizeof (plaintext), plaintext_length,
|
||||
NTP_EF_NTS_COOKIE, cookie,
|
||||
i == 0 ? cookie_length : random() % (cookie_length + 1) / 4 * 4,
|
||||
&ef_length));
|
||||
plaintext_length += ef_length;
|
||||
}
|
||||
}
|
||||
auth_start = info->length;
|
||||
if (index != 4) {
|
||||
if (index == 5) {
|
||||
assert(plaintext_length + 16 <= sizeof (plaintext));
|
||||
memset(plaintext + plaintext_length, 0, 16);
|
||||
plaintext_length += 16;
|
||||
}
|
||||
siv = SIV_CreateInstance(inst->context.algorithm);
|
||||
TEST_CHECK(siv);
|
||||
TEST_CHECK(SIV_SetKey(siv, inst->context.s2c.key, inst->context.s2c.length));
|
||||
@@ -186,8 +206,10 @@ prepare_response(NNC_Instance inst, NTP_Packet *packet, NTP_PacketInfo *info, in
|
||||
min_auth_length));
|
||||
SIV_DestroyInstance(siv);
|
||||
}
|
||||
if (index == 5)
|
||||
if (index == 6)
|
||||
((unsigned char *)packet)[auth_start + 8]++;
|
||||
if (index == 7)
|
||||
TEST_CHECK(NEF_AddField(packet, info, 0x7000, inst->uniq_id, sizeof (inst->uniq_id)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -200,6 +222,8 @@ test_unit(void)
|
||||
IPAddr ip_addr;
|
||||
int i, j, prev_num_cookies, valid;
|
||||
|
||||
TEST_CHECK(SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256) > 0);
|
||||
|
||||
SCK_GetLoopbackIPAddress(AF_INET, &addr.ip_addr);
|
||||
addr.port = 0;
|
||||
|
||||
@@ -233,7 +257,7 @@ test_unit(void)
|
||||
|
||||
if (valid) {
|
||||
TEST_CHECK(NNC_CheckResponseAuth(inst, &packet, &info));
|
||||
TEST_CHECK(inst->num_cookies == MIN(NTS_MAX_COOKIES, prev_num_cookies + 1));
|
||||
TEST_CHECK(inst->num_cookies >= MIN(NTS_MAX_COOKIES, prev_num_cookies + 1));
|
||||
TEST_CHECK(inst->ok_response);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user