mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-04 09:25:06 -05:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad8fb64276 | ||
|
|
436c1d3ea2 | ||
|
|
7fc5da5f80 | ||
|
|
105b3faa46 | ||
|
|
709223826f | ||
|
|
eace93f2af | ||
|
|
2775846db7 | ||
|
|
4aff08e95d | ||
|
|
958d66f8a7 | ||
|
|
85fa29c43d | ||
|
|
0344b9a9c9 | ||
|
|
04f6329773 | ||
|
|
d690faeb19 | ||
|
|
0b2e77ae64 | ||
|
|
2a4fd0a5c6 | ||
|
|
e569e1c9d9 | ||
|
|
7be360041c | ||
|
|
2fa83b541c | ||
|
|
8db9d59dac | ||
|
|
adcf073484 | ||
|
|
5296858411 | ||
|
|
d603426389 | ||
|
|
d3f4292968 | ||
|
|
4dde7198c8 | ||
|
|
b145d3ff51 | ||
|
|
9b98247d9c | ||
|
|
eedabb3d27 | ||
|
|
66dc2b6d6b | ||
|
|
bcdbbbd694 | ||
|
|
7b07e47c08 | ||
|
|
a608496faf | ||
|
|
c687224a11 | ||
|
|
a6f2a613f3 | ||
|
|
cfa39af345 | ||
|
|
8bab35c122 | ||
|
|
b20ef4cd7f | ||
|
|
b8b751a932 | ||
|
|
4a390841eb | ||
|
|
f506f44033 | ||
|
|
1f8355f154 | ||
|
|
ddc2761498 |
5
NEWS
5
NEWS
@@ -7,13 +7,14 @@ Enhancements
|
||||
* Add support for AES-CMAC keys (AES128, AES256) with Nettle
|
||||
* Add support for maxsamples of 1 for faster update with -q/-Q option
|
||||
* Add -L option to limit log messages by severity
|
||||
* Avoid replacing NTP sources with unreachable addresses
|
||||
* Avoid replacing NTP sources with sources that have unreachable address
|
||||
* Improve pools to repeat name resolution to get "maxsources" sources
|
||||
* Improve NTP loop test to prevent synchronisation to itself
|
||||
* Update clock synchronisation status and leap status more frequently
|
||||
* Update seccomp filter
|
||||
* Add "add pool" command
|
||||
* Add -N option and sourcename command to print original names of sources
|
||||
* Add -a option to source/sourcestats command to print unresolved sources
|
||||
* Add -a option to sources/sourcestats command to print unresolved sources
|
||||
* Add reset command to drop all measurements
|
||||
|
||||
Bug fixes
|
||||
|
||||
1
README
1
README
@@ -112,6 +112,7 @@ Benny Lyne Amorsen <benny@amorsen.dk>
|
||||
Andrew Bishop <amb@gedanken.demon.co.uk>
|
||||
Vincent Blut <vincent.debian@free.fr>
|
||||
Stephan I. Boettcher <stephan@nevis1.columbia.edu>
|
||||
David Bohman <debohman@gmail.com>
|
||||
Goswin Brederlow <brederlo@informatik.uni-tuebingen.de>
|
||||
Leigh Brown <leigh@solinno.co.uk>
|
||||
Erik Bryer <ebryer@spots.ab.ca>
|
||||
|
||||
4
client.c
4
client.c
@@ -1267,8 +1267,8 @@ give_help(void)
|
||||
"\0\0"
|
||||
"Other daemon commands:\0\0"
|
||||
"cyclelogs\0Close and re-open log files\0"
|
||||
"dump\0Dump all measurements to save files\0"
|
||||
"rekey\0Re-read keys from key file\0"
|
||||
"dump\0Dump measurements and NTS keys/cookies\0"
|
||||
"rekey\0Re-read keys\0"
|
||||
"reset\0Drop all measurements\0"
|
||||
"shutdown\0Stop daemon\0"
|
||||
"\0\0"
|
||||
|
||||
31
cmdmon.c
31
cmdmon.c
@@ -44,6 +44,7 @@
|
||||
#include "reference.h"
|
||||
#include "manual.h"
|
||||
#include "memory.h"
|
||||
#include "nts_ke_server.h"
|
||||
#include "local.h"
|
||||
#include "addrfilt.h"
|
||||
#include "conf.h"
|
||||
@@ -309,6 +310,8 @@ static void
|
||||
handle_dump(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
SRC_DumpSources();
|
||||
NSR_DumpAuthData();
|
||||
NKS_DumpKeys();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -617,6 +620,7 @@ static void
|
||||
handle_rekey(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
KEY_Reload();
|
||||
NKS_ReloadKeys();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1237,7 +1241,7 @@ handle_reset(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
static void
|
||||
read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
{
|
||||
SCK_Message sck_message;
|
||||
SCK_Message *sck_message;
|
||||
CMD_Request rx_message;
|
||||
CMD_Reply tx_message;
|
||||
IPAddr loopback_addr, remote_ip;
|
||||
@@ -1246,26 +1250,27 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
unsigned short rx_command;
|
||||
struct timespec now, cooked_now;
|
||||
|
||||
if (!SCK_ReceiveMessage(sock_fd, &sck_message, 0))
|
||||
sck_message = SCK_ReceiveMessage(sock_fd, 0);
|
||||
if (!sck_message)
|
||||
return;
|
||||
|
||||
read_length = sck_message.length;
|
||||
read_length = sck_message->length;
|
||||
|
||||
/* Get current time cheaply */
|
||||
SCH_GetLastEventTime(&cooked_now, NULL, &now);
|
||||
|
||||
/* Check if it's from localhost (127.0.0.1, ::1, or Unix domain),
|
||||
or an authorised address */
|
||||
switch (sck_message.addr_type) {
|
||||
switch (sck_message->addr_type) {
|
||||
case SCK_ADDR_IP:
|
||||
assert(sock_fd == sock_fd4 || sock_fd == sock_fd6);
|
||||
remote_ip = sck_message.remote_addr.ip.ip_addr;
|
||||
remote_ip = sck_message->remote_addr.ip.ip_addr;
|
||||
SCK_GetLoopbackIPAddress(remote_ip.family, &loopback_addr);
|
||||
localhost = UTI_CompareIPs(&remote_ip, &loopback_addr, NULL) == 0;
|
||||
|
||||
if (!localhost && !ADF_IsAllowed(access_auth_table, &remote_ip)) {
|
||||
DEBUG_LOG("Unauthorised host %s",
|
||||
UTI_IPSockAddrToString(&sck_message.remote_addr.ip));
|
||||
UTI_IPSockAddrToString(&sck_message->remote_addr.ip));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1291,7 +1296,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&rx_message, sck_message.data, read_length);
|
||||
memcpy(&rx_message, sck_message->data, read_length);
|
||||
|
||||
if (rx_message.pkt_type != PKT_TYPE_CMD_REQUEST ||
|
||||
rx_message.res1 != 0 ||
|
||||
@@ -1313,8 +1318,8 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
rx_command = ntohs(rx_message.command);
|
||||
|
||||
memset(&tx_message, 0, sizeof (tx_message));
|
||||
sck_message.data = &tx_message;
|
||||
sck_message.length = 0;
|
||||
sck_message->data = &tx_message;
|
||||
sck_message->length = 0;
|
||||
|
||||
tx_message.version = PROTO_VERSION_NUMBER;
|
||||
tx_message.pkt_type = PKT_TYPE_CMD_REPLY;
|
||||
@@ -1329,7 +1334,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
|
||||
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT_SERVER) {
|
||||
tx_message.status = htons(STT_BADPKTVERSION);
|
||||
transmit_reply(sock_fd, &sck_message);
|
||||
transmit_reply(sock_fd, sck_message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1339,7 +1344,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
DEBUG_LOG("Command packet has invalid command %d", rx_command);
|
||||
|
||||
tx_message.status = htons(STT_INVALID);
|
||||
transmit_reply(sock_fd, &sck_message);
|
||||
transmit_reply(sock_fd, sck_message);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1348,7 +1353,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
expected_length);
|
||||
|
||||
tx_message.status = htons(STT_BADPKTLENGTH);
|
||||
transmit_reply(sock_fd, &sck_message);
|
||||
transmit_reply(sock_fd, sck_message);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1629,7 +1634,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
static int do_it=1;
|
||||
|
||||
if (do_it) {
|
||||
transmit_reply(sock_fd, &sck_message);
|
||||
transmit_reply(sock_fd, sck_message);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
40
conf.c
40
conf.c
@@ -223,8 +223,9 @@ static char *leapsec_tz = NULL;
|
||||
/* Name of the user to which will be dropped root privileges. */
|
||||
static char *user;
|
||||
|
||||
/* NTS cache dir, certificates, private key, and port */
|
||||
static char *nts_cachedir = NULL;
|
||||
/* NTS server and client configuration */
|
||||
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;
|
||||
@@ -234,6 +235,9 @@ static int nts_refresh = 2419200; /* 4 weeks */
|
||||
static int nts_rotate = 604800; /* 1 week */
|
||||
static char *nts_trusted_cert_file = NULL;
|
||||
|
||||
/* Number of clock updates needed to enable certificate time checks */
|
||||
static int no_cert_time_check = 0;
|
||||
|
||||
/* Flag disabling use of system trusted certificates */
|
||||
static int no_system_cert = 0;
|
||||
|
||||
@@ -404,7 +408,8 @@ CNF_Finalise(void)
|
||||
Free(mail_user_on_change);
|
||||
Free(tempcomp_sensor_file);
|
||||
Free(tempcomp_point_file);
|
||||
Free(nts_cachedir);
|
||||
Free(nts_dump_dir);
|
||||
Free(nts_ntp_server);
|
||||
Free(nts_server_cert_file);
|
||||
Free(nts_server_key_file);
|
||||
Free(nts_trusted_cert_file);
|
||||
@@ -543,6 +548,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
parse_int(p, &min_samples);
|
||||
} else if (!strcasecmp(command, "minsources")) {
|
||||
parse_int(p, &min_sources);
|
||||
} else if (!strcasecmp(command, "nocerttimecheck")) {
|
||||
parse_int(p, &no_cert_time_check);
|
||||
} else if (!strcasecmp(command, "noclientlog")) {
|
||||
no_client_log = parse_null(p);
|
||||
} else if (!strcasecmp(command, "nosystemcert")) {
|
||||
@@ -551,8 +558,11 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
parse_string(p, &ntp_signd_socket);
|
||||
} else if (!strcasecmp(command, "ntstrustedcerts")) {
|
||||
parse_string(p, &nts_trusted_cert_file);
|
||||
} else if (!strcasecmp(command, "ntscachedir")) {
|
||||
parse_string(p, &nts_cachedir);
|
||||
} else if (!strcasecmp(command, "ntscachedir") ||
|
||||
!strcasecmp(command, "ntsdumpdir")) {
|
||||
parse_string(p, &nts_dump_dir);
|
||||
} else if (!strcasecmp(command, "ntsntpserver")) {
|
||||
parse_string(p, &nts_ntp_server);
|
||||
} else if (!strcasecmp(command, "ntsport")) {
|
||||
parse_int(p, &nts_server_port);
|
||||
} else if (!strcasecmp(command, "ntsprocesses")) {
|
||||
@@ -2069,9 +2079,17 @@ CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface)
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetNtsCacheDir(void)
|
||||
CNF_GetNtsDumpDir(void)
|
||||
{
|
||||
return nts_cachedir;
|
||||
return nts_dump_dir;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetNtsNtpServer(void)
|
||||
{
|
||||
return nts_ntp_server;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -2145,3 +2163,11 @@ CNF_GetNoSystemCert(void)
|
||||
{
|
||||
return no_system_cert;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetNoCertTimeCheck(void)
|
||||
{
|
||||
return no_cert_time_check;
|
||||
}
|
||||
|
||||
4
conf.h
4
conf.h
@@ -139,7 +139,8 @@ typedef struct {
|
||||
|
||||
extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
|
||||
|
||||
extern char *CNF_GetNtsCacheDir(void);
|
||||
extern char *CNF_GetNtsDumpDir(void);
|
||||
extern char *CNF_GetNtsNtpServer(void);
|
||||
extern char *CNF_GetNtsServerCertFile(void);
|
||||
extern char *CNF_GetNtsServerKeyFile(void);
|
||||
extern int CNF_GetNtsServerPort(void);
|
||||
@@ -149,5 +150,6 @@ extern int CNF_GetNtsRefresh(void);
|
||||
extern int CNF_GetNtsRotate(void);
|
||||
extern char *CNF_GetNtsTrustedCertFile(void);
|
||||
extern int CNF_GetNoSystemCert(void);
|
||||
extern int CNF_GetNoCertTimeCheck(void);
|
||||
|
||||
#endif /* GOT_CONF_H */
|
||||
|
||||
@@ -689,6 +689,21 @@ changes in the frequency and offset of the clock. The offsets in the
|
||||
<<chronyc.adoc#sourcestats,*sourcestats*>> reports (and the _tracking.log_ and
|
||||
_statistics.log_ files) may be smaller than the actual offsets.
|
||||
|
||||
[[ntsdumpdir1]]*ntsdumpdir* _directory_::
|
||||
This directive specifies a directory for the client to save NTS cookies it
|
||||
received from the server in order to avoid making an NTS-KE request when
|
||||
*chronyd* is started again. The cookies are saved separately for each NTP
|
||||
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.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
ntsdumpdir @CHRONYVARDIR@
|
||||
----
|
||||
+
|
||||
This directory is used also by the <<ntsdumpdir2,NTS server>> to save keys.
|
||||
|
||||
[[ntsrefresh]]*ntsrefresh* _interval_::
|
||||
This directive specifies the maximum interval between NTS-KE handshakes (in
|
||||
seconds) in order to refresh the keys authenticating NTP packets. The default
|
||||
@@ -703,6 +718,25 @@ of NTS servers in addition to the system's default trusted CAs (if the
|
||||
[[nosystemcert]]*nosystemcert*::
|
||||
This directive disables the system's default trusted CAs.
|
||||
|
||||
[[nocerttimecheck]]*nocerttimecheck* _limit_::
|
||||
This directive disables the checks of the activation and expiration times of
|
||||
certificates for the specified number of clock updates. It allows the NTS
|
||||
authentication mechanism to be used on computers which start with wrong time
|
||||
(e.g. due to not having an RTC or backup battery). Disabling the time checks
|
||||
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:
|
||||
+
|
||||
----
|
||||
nocerttimecheck 1
|
||||
----
|
||||
+
|
||||
This would disable the time checks until the clock is updated for the first
|
||||
time, assuming the first update corrects the clock and later checks can work
|
||||
with correct time.
|
||||
|
||||
=== Source selection
|
||||
|
||||
[[combinelimit]]*combinelimit* _limit_::
|
||||
@@ -888,7 +922,7 @@ slightly different rates when it is necessary to keep them close together, the
|
||||
enable a server leap smear.
|
||||
+
|
||||
When smearing a leap second, the leap status is suppressed on the server and
|
||||
the served time is corrected slowly be slewing instead of stepping. The clients
|
||||
the served time is corrected slowly by slewing instead of stepping. The clients
|
||||
do not need any special configuration as they do not know there is any leap
|
||||
second and they follow the server time which eventually brings them back to
|
||||
UTC. Care must be taken to ensure they use only NTP servers which smear the
|
||||
@@ -1390,16 +1424,50 @@ process will be started and all NTS-KE requests will be handled by the main
|
||||
This directive specifies the maximum number of concurrent NTS-KE connections
|
||||
per process that the NTS server will accept. The default value is 100.
|
||||
|
||||
[[ntscachedir]]*ntscachedir* _directory_::
|
||||
This directive specifies a directory to save the keys which the NTS server uses
|
||||
to encrypt NTS cookies in order to prevent a storm of NTS-KE handshakes when
|
||||
the server is restarted. By default, the server does not save the keys.
|
||||
[[ntsdumpdir2]]*ntsdumpdir* _directory_::
|
||||
This directive specifies a directory where *chronyd* operating as an NTS server
|
||||
can save the keys which encrypt NTS cookies provided to clients. The keys are
|
||||
saved to a single file named _ntskeys_. When *chronyd* is restarted, reloading
|
||||
the keys allows the clients to continue using old cookies and avoids a storm of
|
||||
NTS-KE requests. By default, the server does not save the keys.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
ntsdumpdir @CHRONYVARDIR@
|
||||
----
|
||||
+
|
||||
This directory is used also by the <<ntsdumpdir1,NTS client>> to save NTS cookies.
|
||||
|
||||
[[ntsntpserver]]*ntsntpserver* _hostname_::
|
||||
This directive specifies the hostname or address of the NTP server(s) which is
|
||||
provided in the NTS-KE response to the clients. It allows the NTS-KE server to
|
||||
be separated from the NTP server. However, the servers need to share the keys,
|
||||
i.e. external key management needs to be enabled by setting
|
||||
<<ntsrotate,*ntsrotate*>> to 0. By default, no hostname or address is provided
|
||||
to the clients, which means they should use the same server for NTS-KE and NTP.
|
||||
|
||||
[[ntsrotate]]*ntsrotate* _interval_::
|
||||
This directive specifies the rotation interval (in seconds) of the server key
|
||||
which encrypts cookies. The server keeps up to 3 previous keys to give the
|
||||
clients enough time to get cookies encrypted by the latest key. The default
|
||||
interval is 604800 (1 week).
|
||||
which encrypts the NTS cookies. New keys are generated automatically. The
|
||||
server keeps two previous keys to give the clients time to get new cookies
|
||||
encrypted by the latest key. The default interval is 604800 seconds (1 week).
|
||||
+
|
||||
The automatic rotation of the keys can be disabled by setting *ntsrotate* to 0.
|
||||
In this case the keys are assumed to be managed externally. *chronyd* will not
|
||||
save the keys to the _ntskeys_ file and will reload the keys from the file when
|
||||
the <<chronyc.adoc#rekey,*rekey*>> command is issued in *chronyc*. The file can
|
||||
be periodically copied from another server running *chronyd* (which does
|
||||
not have *ntsrotate* set to 0) in order to have one or more servers dedicated
|
||||
to NTS-KE. The NTS-KE servers need to be configured with the
|
||||
<<ntsntpname,*ntsntpname*>> directive to point the clients to the right NTP
|
||||
server.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
ntsrotate 2592000
|
||||
----
|
||||
|
||||
[[port]]*port* _port_::
|
||||
This option allows you to configure the port on which *chronyd* will listen for
|
||||
|
||||
@@ -51,7 +51,8 @@ running under a non-root user), it will try to connect to 127.0.0.1 and then
|
||||
|
||||
Only the following monitoring commands, which do not affect the behaviour of
|
||||
*chronyd*, are allowed from the network: *activity*, *manual list*,
|
||||
*rtcdata*, *smoothing*, *sources*, *sourcestats*, *tracking*, *waitsync*. The
|
||||
*rtcdata*, *smoothing*, *sourcename*, *sources*, *sourcestats*, *tracking*,
|
||||
*waitsync*. The
|
||||
set of hosts from which *chronyd* will accept these commands can be configured
|
||||
with the <<chrony.conf.adoc#cmdallow,*cmdallow*>> directive in the *chronyd*'s
|
||||
configuration file or the <<cmdallow,*cmdallow*>> command in *chronyc*. By
|
||||
@@ -1163,13 +1164,18 @@ purged. An example of how to do this is shown below.
|
||||
The *dump* command causes *chronyd* to write its current history of
|
||||
measurements for each of its sources to dump files in the directory specified
|
||||
in the configuration file by the <<chrony.conf.adoc#dumpdir,*dumpdir*>>
|
||||
directive and also write server NTS keys and client NTS cookies to the
|
||||
directory specified by the <<chrony.conf.adoc#ntsdumpdir1,*ntsdumpdir*>>
|
||||
directive. Note that *chronyd* does this automatically when it exits. This
|
||||
command is mainly useful for inspection of the history whilst *chronyd* is
|
||||
running.
|
||||
command is mainly useful for inspection whilst *chronyd* is running.
|
||||
|
||||
[[rekey]]*rekey*::
|
||||
The *rekey* command causes *chronyd* to re-read the key file specified in the
|
||||
configuration file by the <<chrony.conf.adoc#keyfile,*keyfile*>> directive.
|
||||
configuration file by the <<chrony.conf.adoc#keyfile,*keyfile*>> directive. It
|
||||
also re-reads the server NTS keys if
|
||||
<<chrony.conf.adoc#ntsdumpdir2,*ntsdumpdir*>> is specified and
|
||||
<<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
|
||||
|
||||
14
ntp_auth.c
14
ntp_auth.c
@@ -484,3 +484,17 @@ NAU_ChangeAddress(NAU_Instance instance, IPAddr *address)
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NAU_DumpData(NAU_Instance instance)
|
||||
{
|
||||
switch (instance->mode) {
|
||||
case NTP_AUTH_NTS:
|
||||
NNC_DumpData(instance->nts);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,4 +86,7 @@ extern int NAU_CheckResponseAuth(NAU_Instance instance, NTP_Packet *response,
|
||||
/* Change an authentication-specific address (e.g. after replacing a source) */
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
||||
16
ntp_core.c
16
ntp_core.c
@@ -703,6 +703,11 @@ NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr, int
|
||||
{
|
||||
memset(&inst->report, 0, sizeof (inst->report));
|
||||
NCR_ResetInstance(inst);
|
||||
|
||||
/* Update the authentication-specific address before NTP address */
|
||||
if (!ntp_only)
|
||||
NAU_ChangeAddress(inst->auth, &remote_addr->ip_addr);
|
||||
|
||||
inst->remote_addr = *remote_addr;
|
||||
|
||||
if (inst->mode == MODE_CLIENT)
|
||||
@@ -718,9 +723,6 @@ NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr, int
|
||||
SRC_SetRefid(inst->source, UTI_IPToRefid(&remote_addr->ip_addr),
|
||||
&inst->remote_addr.ip_addr);
|
||||
SRC_ResetInstance(inst->source);
|
||||
|
||||
if (!ntp_only)
|
||||
NAU_ChangeAddress(inst->auth, &remote_addr->ip_addr);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -2560,6 +2562,14 @@ int NCR_IsSyncPeer(NCR_Instance inst)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NCR_DumpAuthData(NCR_Instance inst)
|
||||
{
|
||||
NAU_DumpData(inst->auth);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
broadcast_timeout(void *arg)
|
||||
{
|
||||
|
||||
@@ -136,6 +136,8 @@ extern uint32_t NCR_GetLocalRefid(NCR_Instance inst);
|
||||
|
||||
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);
|
||||
|
||||
#endif /* GOT_NTP_CORE_H */
|
||||
|
||||
9
ntp_io.c
9
ntp_io.c
@@ -404,10 +404,7 @@ process_message(SCK_Message *message, int sock_fd, int event)
|
||||
static void
|
||||
read_from_socket(int sock_fd, int event, void *anything)
|
||||
{
|
||||
/* This should only be called when there is something
|
||||
to read, otherwise it may block */
|
||||
|
||||
SCK_Message messages[SCK_MAX_RECV_MESSAGES];
|
||||
SCK_Message *messages;
|
||||
int i, received, flags = 0;
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
@@ -423,8 +420,8 @@ read_from_socket(int sock_fd, int event, void *anything)
|
||||
#endif
|
||||
}
|
||||
|
||||
received = SCK_ReceiveMessages(sock_fd, messages, SCK_MAX_RECV_MESSAGES, flags);
|
||||
if (received <= 0)
|
||||
messages = SCK_ReceiveMessages(sock_fd, flags, &received);
|
||||
if (!messages)
|
||||
return;
|
||||
|
||||
for (i = 0; i < received; i++)
|
||||
|
||||
@@ -381,7 +381,7 @@ change_source_address(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr
|
||||
name = record->name;
|
||||
severity = UTI_IsIPReal(&old_addr->ip_addr) ? LOGS_INFO : LOGS_DEBUG;
|
||||
|
||||
if (slot1 != slot2) {
|
||||
if (found == 0) {
|
||||
/* The hash table must be rebuilt for the changed address */
|
||||
rehash_records();
|
||||
|
||||
@@ -1297,6 +1297,18 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NSR_DumpAuthData(void)
|
||||
{
|
||||
SourceRecord *record;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(records); i++) {
|
||||
record = get_record(i);
|
||||
if (!record->remote_addr)
|
||||
continue;
|
||||
NCR_DumpAuthData(record->data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,4 +140,6 @@ extern int NSR_GetNTPReport(RPT_NTPReport *report);
|
||||
|
||||
extern void NSR_GetActivityReport(RPT_ActivityReport *report);
|
||||
|
||||
extern void NSR_DumpAuthData(void);
|
||||
|
||||
#endif /* GOT_NTP_SOURCES_H */
|
||||
|
||||
12
nts_ke.h
12
nts_ke.h
@@ -46,7 +46,7 @@
|
||||
#define NKE_ERROR_INTERNAL_SERVER_ERROR 2
|
||||
|
||||
#define NKE_ALPN_NAME "ntske/1"
|
||||
#define NKE_EXPORTER_LABEL "EXPORTER-network-time-security/1"
|
||||
#define NKE_EXPORTER_LABEL "EXPORTER-network-time-security"
|
||||
#define NKE_EXPORTER_CONTEXT_C2S "\x0\x0\x0\xf\x0"
|
||||
#define NKE_EXPORTER_CONTEXT_S2C "\x0\x0\x0\xf\x1"
|
||||
|
||||
@@ -56,11 +56,21 @@
|
||||
#define NKE_MAX_COOKIES 8
|
||||
#define NKE_MAX_KEY_LENGTH SIV_MAX_KEY_LENGTH
|
||||
|
||||
#define NKE_RETRY_FACTOR2_CONNECT 4
|
||||
#define NKE_RETRY_FACTOR2_TLS 10
|
||||
#define NKE_MAX_RETRY_INTERVAL2 19
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
unsigned char key[NKE_MAX_KEY_LENGTH];
|
||||
} NKE_Key;
|
||||
|
||||
typedef struct {
|
||||
SIV_Algorithm algorithm;
|
||||
NKE_Key c2s;
|
||||
NKE_Key s2c;
|
||||
} NKE_Context;
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
unsigned char cookie[NKE_MAX_COOKIE_LENGTH];
|
||||
|
||||
@@ -49,8 +49,7 @@ struct NKC_Instance_Record {
|
||||
int got_response;
|
||||
int resolving_name;
|
||||
|
||||
SIV_Algorithm siv_algorithm;
|
||||
NKE_Key c2s, s2c;
|
||||
NKE_Context context;
|
||||
NKE_Cookie cookies[NKE_MAX_COOKIES];
|
||||
int num_cookies;
|
||||
char server_name[NKE_MAX_RECORD_BODY_LENGTH + 1];
|
||||
@@ -156,7 +155,7 @@ process_response(NKC_Instance inst)
|
||||
break;
|
||||
}
|
||||
aead_algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
inst->siv_algorithm = aead_algorithm;
|
||||
inst->context.algorithm = aead_algorithm;
|
||||
break;
|
||||
case NKE_RECORD_ERROR:
|
||||
if (length == 2)
|
||||
@@ -237,7 +236,8 @@ handle_message(void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!NKSN_GetKeys(inst->session, inst->siv_algorithm, &inst->c2s, &inst->s2c))
|
||||
if (!NKSN_GetKeys(inst->session, inst->context.algorithm,
|
||||
&inst->context.c2s, &inst->context.s2c))
|
||||
return 0;
|
||||
|
||||
if (inst->server_name[0] != '\0') {
|
||||
@@ -318,6 +318,7 @@ int
|
||||
NKC_Start(NKC_Instance inst)
|
||||
{
|
||||
IPSockAddr local_addr;
|
||||
char label[512];
|
||||
int sock_fd;
|
||||
|
||||
assert(!NKC_IsActive(inst));
|
||||
@@ -338,8 +339,13 @@ NKC_Start(NKC_Instance inst)
|
||||
if (sock_fd < 0)
|
||||
return 0;
|
||||
|
||||
/* Make a label containing both the address and name of the server */
|
||||
if (snprintf(label, sizeof (label), "%s (%s)",
|
||||
UTI_IPSockAddrToString(&inst->address), inst->name) >= sizeof (label))
|
||||
;
|
||||
|
||||
/* Start a NTS-KE session */
|
||||
if (!NKSN_StartSession(inst->session, sock_fd, client_credentials, CLIENT_TIMEOUT)) {
|
||||
if (!NKSN_StartSession(inst->session, sock_fd, label, client_credentials, CLIENT_TIMEOUT)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -365,8 +371,7 @@ NKC_IsActive(NKC_Instance inst)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NKC_GetNtsData(NKC_Instance inst,
|
||||
SIV_Algorithm *siv_algorithm, NKE_Key *c2s, NKE_Key *s2c,
|
||||
NKC_GetNtsData(NKC_Instance inst, NKE_Context *context,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
|
||||
IPSockAddr *ntp_address)
|
||||
{
|
||||
@@ -375,9 +380,7 @@ NKC_GetNtsData(NKC_Instance inst,
|
||||
if (!inst->got_response || inst->resolving_name)
|
||||
return 0;
|
||||
|
||||
*siv_algorithm = inst->siv_algorithm;
|
||||
*c2s = inst->c2s;
|
||||
*s2c = inst->s2c;
|
||||
*context = inst->context;
|
||||
|
||||
for (i = 0; i < inst->num_cookies && i < max_cookies; i++)
|
||||
cookies[i] = inst->cookies[i];
|
||||
@@ -387,3 +390,11 @@ NKC_GetNtsData(NKC_Instance inst,
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NKC_GetRetryFactor(NKC_Instance inst)
|
||||
{
|
||||
return NKSN_GetRetryFactor(inst->session);
|
||||
}
|
||||
|
||||
@@ -50,9 +50,11 @@ extern int NKC_Start(NKC_Instance inst);
|
||||
extern int NKC_IsActive(NKC_Instance inst);
|
||||
|
||||
/* Get the NTS data if the session was successful */
|
||||
extern int NKC_GetNtsData(NKC_Instance inst,
|
||||
SIV_Algorithm *siv_algorithm, NKE_Key *c2s, NKE_Key *s2c,
|
||||
extern int NKC_GetNtsData(NKC_Instance inst, NKE_Context *context,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
|
||||
IPSockAddr *ntp_address);
|
||||
|
||||
/* Get a factor to calculate retry interval (in log2 seconds) */
|
||||
extern int NKC_GetRetryFactor(NKC_Instance inst);
|
||||
|
||||
#endif
|
||||
|
||||
212
nts_ke_server.c
212
nts_ke_server.c
@@ -50,8 +50,10 @@
|
||||
|
||||
#define KEY_ID_INDEX_BITS 2
|
||||
#define MAX_SERVER_KEYS (1U << KEY_ID_INDEX_BITS)
|
||||
#define FUTURE_KEYS 1
|
||||
|
||||
#define MIN_KEY_ROTATE_INTERVAL 1.0
|
||||
#define DUMP_FILENAME "ntskeys"
|
||||
#define DUMP_IDENTIFIER "NKS0\n"
|
||||
|
||||
#define INVALID_SOCK_FD (-7)
|
||||
|
||||
@@ -78,6 +80,8 @@ typedef struct {
|
||||
|
||||
static ServerKey server_keys[MAX_SERVER_KEYS];
|
||||
static int current_server_key;
|
||||
static double last_server_key_ts;
|
||||
static int key_rotation_interval;
|
||||
|
||||
static int server_sock_fd4;
|
||||
static int server_sock_fd6;
|
||||
@@ -113,7 +117,7 @@ handle_client(int sock_fd, IPSockAddr *addr)
|
||||
instp = ARR_GetElement(sessions, i);
|
||||
if (!*instp) {
|
||||
/* NULL handler arg will be replaced with the session instance */
|
||||
inst = NKSN_CreateInstance(1, UTI_IPSockAddrToString(addr), handle_message, NULL);
|
||||
inst = NKSN_CreateInstance(1, NULL, handle_message, NULL);
|
||||
*instp = inst;
|
||||
break;
|
||||
} else if (NKSN_IsStopped(*instp)) {
|
||||
@@ -128,7 +132,8 @@ handle_client(int sock_fd, IPSockAddr *addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!NKSN_StartSession(inst, sock_fd, server_credentials, SERVER_TIMEOUT))
|
||||
if (!NKSN_StartSession(inst, sock_fd, UTI_IPSockAddrToString(addr),
|
||||
server_credentials, SERVER_TIMEOUT))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -139,28 +144,29 @@ handle_client(int sock_fd, IPSockAddr *addr)
|
||||
static void
|
||||
handle_helper_request(int fd, int event, void *arg)
|
||||
{
|
||||
SCK_Message message;
|
||||
SCK_Message *message;
|
||||
HelperRequest *req;
|
||||
IPSockAddr client_addr;
|
||||
int sock_fd;
|
||||
|
||||
if (!SCK_ReceiveMessage(fd, &message, SCK_FLAG_MSG_DESCRIPTOR))
|
||||
message = SCK_ReceiveMessage(fd, SCK_FLAG_MSG_DESCRIPTOR);
|
||||
if (!message)
|
||||
return;
|
||||
|
||||
sock_fd = message.descriptor;
|
||||
sock_fd = message->descriptor;
|
||||
if (sock_fd < 0) {
|
||||
/* Message with no descriptor is a shutdown command */
|
||||
SCH_QuitProgram();
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.length != sizeof (HelperRequest)) {
|
||||
if (message->length != sizeof (HelperRequest)) {
|
||||
DEBUG_LOG("Unexpected message length");
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
req = message.data;
|
||||
req = message->data;
|
||||
|
||||
/* Extract the server key and client address from the request */
|
||||
server_keys[current_server_key].id = ntohl(req->key_id);
|
||||
@@ -291,8 +297,9 @@ helper_signal(int x)
|
||||
static int
|
||||
prepare_response(NKSN_Instance session, int error, int next_protocol, int aead_algorithm)
|
||||
{
|
||||
NKE_Context context;
|
||||
NKE_Cookie cookie;
|
||||
NKE_Key c2s, s2c;
|
||||
char *ntp_server;
|
||||
uint16_t datum;
|
||||
int i;
|
||||
|
||||
@@ -319,19 +326,20 @@ prepare_response(NKSN_Instance session, int error, int next_protocol, int aead_a
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This should be configurable */
|
||||
if (0) {
|
||||
const char server[] = "::1";
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NTPV4_SERVER_NEGOTIATION, server,
|
||||
sizeof (server) - 1))
|
||||
ntp_server = CNF_GetNtsNtpServer();
|
||||
if (ntp_server) {
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NTPV4_SERVER_NEGOTIATION,
|
||||
ntp_server, strlen(ntp_server)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!NKSN_GetKeys(session, aead_algorithm, &c2s, &s2c))
|
||||
context.algorithm = aead_algorithm;
|
||||
|
||||
if (!NKSN_GetKeys(session, aead_algorithm, &context.c2s, &context.s2c))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < NKE_MAX_COOKIES; i++) {
|
||||
if (!NKS_GenerateCookie(&c2s, &s2c, &cookie))
|
||||
if (!NKS_GenerateCookie(&context, &cookie))
|
||||
return 0;
|
||||
if (!NKSN_AddRecord(session, 0, NKE_RECORD_COOKIE, cookie.cookie, cookie.length))
|
||||
return 0;
|
||||
@@ -434,6 +442,8 @@ generate_key(int index)
|
||||
server_keys[index].id |= index;
|
||||
|
||||
DEBUG_LOG("Generated server key %"PRIX32, server_keys[index].id);
|
||||
|
||||
last_server_key_ts = SCH_GetLastEventMonoTime();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -441,77 +451,96 @@ generate_key(int index)
|
||||
static void
|
||||
save_keys(void)
|
||||
{
|
||||
char hex_key[SIV_MAX_KEY_LENGTH * 2 + 1];
|
||||
char buf[SIV_MAX_KEY_LENGTH * 2 + 1], *dump_dir;
|
||||
int i, index, key_length;
|
||||
char *cachedir;
|
||||
double last_key_age;
|
||||
FILE *f;
|
||||
|
||||
cachedir = CNF_GetNtsCacheDir();
|
||||
if (!cachedir)
|
||||
/* Don't save the keys if rotation is disabled to enable an external
|
||||
management of the keys (e.g. share them with another server) */
|
||||
if (key_rotation_interval == 0)
|
||||
return;
|
||||
|
||||
f = UTI_OpenFile(cachedir, "ntskeys", ".tmp", 'w', 0600);
|
||||
dump_dir = CNF_GetNtsDumpDir();
|
||||
if (!dump_dir)
|
||||
return;
|
||||
|
||||
f = UTI_OpenFile(dump_dir, DUMP_FILENAME, ".tmp", 'w', 0600);
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
key_length = SIV_GetKeyLength(SERVER_COOKIE_SIV);
|
||||
last_key_age = SCH_GetLastEventMonoTime() - last_server_key_ts;
|
||||
|
||||
if (fprintf(f, "%s%d %.1f\n", DUMP_IDENTIFIER, SERVER_COOKIE_SIV, last_key_age) < 0)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < MAX_SERVER_KEYS; i++) {
|
||||
index = (current_server_key + i + 1) % MAX_SERVER_KEYS;
|
||||
index = (current_server_key + i + 1 + FUTURE_KEYS) % MAX_SERVER_KEYS;
|
||||
|
||||
if (key_length > sizeof (server_keys[index].key) ||
|
||||
!UTI_BytesToHex(server_keys[index].key, key_length, hex_key, sizeof (hex_key))) {
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(f, "%08"PRIX32" %s\n", server_keys[index].id, hex_key);
|
||||
!UTI_BytesToHex(server_keys[index].key, key_length, buf, sizeof (buf)) ||
|
||||
fprintf(f, "%08"PRIX32" %s\n", server_keys[index].id, buf) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (!UTI_RenameTempFile(cachedir, "ntskeys", ".tmp", NULL))
|
||||
if (!UTI_RenameTempFile(dump_dir, DUMP_FILENAME, ".tmp", NULL)) {
|
||||
if (!UTI_RemoveFile(dump_dir, DUMP_FILENAME, ".tmp"))
|
||||
;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
DEBUG_LOG("Could not %s server keys", "save");
|
||||
fclose(f);
|
||||
|
||||
if (!UTI_RemoveFile(dump_dir, DUMP_FILENAME, NULL))
|
||||
;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define MAX_WORDS 2
|
||||
|
||||
static void
|
||||
load_keys(void)
|
||||
{
|
||||
int i, index, line_length, key_length, n;
|
||||
char *cachedir, line[1024];
|
||||
char *dump_dir, line[1024], *words[MAX_WORDS];
|
||||
int i, index, key_length, algorithm;
|
||||
double key_age;
|
||||
FILE *f;
|
||||
uint32_t id;
|
||||
|
||||
cachedir = CNF_GetNtsCacheDir();
|
||||
if (!cachedir)
|
||||
dump_dir = CNF_GetNtsDumpDir();
|
||||
if (!dump_dir)
|
||||
return;
|
||||
|
||||
f = UTI_OpenFile(cachedir, "ntskeys", NULL, 'r', 0);
|
||||
f = UTI_OpenFile(dump_dir, DUMP_FILENAME, NULL, 'r', 0);
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
if (!fgets(line, sizeof (line), f) || strcmp(line, DUMP_IDENTIFIER) != 0 ||
|
||||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 2 ||
|
||||
sscanf(words[0], "%d", &algorithm) != 1 || algorithm != SERVER_COOKIE_SIV ||
|
||||
sscanf(words[1], "%lf", &key_age) != 1)
|
||||
goto error;
|
||||
|
||||
key_length = SIV_GetKeyLength(SERVER_COOKIE_SIV);
|
||||
last_server_key_ts = SCH_GetLastEventMonoTime() - MAX(key_age, 0.0);
|
||||
|
||||
for (i = 0; i < MAX_SERVER_KEYS; i++) {
|
||||
if (!fgets(line, sizeof (line), f))
|
||||
break;
|
||||
|
||||
line_length = strlen(line);
|
||||
if (line_length < 10)
|
||||
break;
|
||||
/* Drop '\n' */
|
||||
line[line_length - 1] = '\0';
|
||||
|
||||
if (sscanf(line, "%"PRIX32"%n", &id, &n) != 1 || line[n] != ' ')
|
||||
break;
|
||||
for (i = 0; i < MAX_SERVER_KEYS && fgets(line, sizeof (line), f); i++) {
|
||||
if (UTI_SplitString(line, words, MAX_WORDS) != 2 ||
|
||||
sscanf(words[0], "%"PRIX32, &id) != 1)
|
||||
goto error;
|
||||
|
||||
index = id % MAX_SERVER_KEYS;
|
||||
|
||||
if (UTI_HexToBytes(line + n + 1, server_keys[index].key,
|
||||
if (UTI_HexToBytes(words[1], server_keys[index].key,
|
||||
sizeof (server_keys[index].key)) != key_length)
|
||||
break;
|
||||
goto error;
|
||||
|
||||
server_keys[index].id = id;
|
||||
if (!SIV_SetKey(server_keys[index].siv, server_keys[index].key, key_length))
|
||||
@@ -519,10 +548,16 @@ load_keys(void)
|
||||
|
||||
DEBUG_LOG("Loaded key %"PRIX32, id);
|
||||
|
||||
current_server_key = index;
|
||||
current_server_key = (index + MAX_SERVER_KEYS - FUTURE_KEYS) % MAX_SERVER_KEYS;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
DEBUG_LOG("Could not %s server keys", "load");
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -531,11 +566,10 @@ static void
|
||||
key_timeout(void *arg)
|
||||
{
|
||||
current_server_key = (current_server_key + 1) % MAX_SERVER_KEYS;
|
||||
generate_key(current_server_key);
|
||||
generate_key((current_server_key + FUTURE_KEYS) % MAX_SERVER_KEYS);
|
||||
save_keys();
|
||||
|
||||
SCH_AddTimeoutByDelay(MAX(CNF_GetNtsRotate(), MIN_KEY_ROTATE_INTERVAL),
|
||||
key_timeout, NULL);
|
||||
SCH_AddTimeoutByDelay(key_rotation_interval, key_timeout, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -582,6 +616,7 @@ NKS_Initialise(int scfilter_level)
|
||||
{
|
||||
char *cert, *key;
|
||||
int i, processes;
|
||||
double key_delay;
|
||||
|
||||
server_sock_fd4 = INVALID_SOCK_FD;
|
||||
server_sock_fd6 = INVALID_SOCK_FD;
|
||||
@@ -615,7 +650,12 @@ NKS_Initialise(int scfilter_level)
|
||||
|
||||
load_keys();
|
||||
|
||||
key_timeout(NULL);
|
||||
key_rotation_interval = MAX(CNF_GetNtsRotate(), 0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
processes = CNF_GetNtsServerProcesses();
|
||||
|
||||
@@ -623,6 +663,8 @@ NKS_Initialise(int scfilter_level)
|
||||
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);
|
||||
@@ -674,10 +716,31 @@ NKS_Finalise(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NKS_DumpKeys(void)
|
||||
{
|
||||
save_keys();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NKS_ReloadKeys(void)
|
||||
{
|
||||
/* Don't load the keys if they are expected to be generated by this server
|
||||
instance (i.e. they are already loaded) to not delay the next rotation */
|
||||
if (key_rotation_interval > 0)
|
||||
return;
|
||||
|
||||
load_keys();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* A server cookie consists of key ID, nonce, and encrypted C2S+S2C keys */
|
||||
|
||||
int
|
||||
NKS_GenerateCookie(NKE_Key *c2s, NKE_Key *s2c, NKE_Cookie *cookie)
|
||||
NKS_GenerateCookie(NKE_Context *context, NKE_Cookie *cookie)
|
||||
{
|
||||
unsigned char plaintext[2 * NKE_MAX_KEY_LENGTH], *ciphertext;
|
||||
int plaintext_length, tag_length;
|
||||
@@ -689,8 +752,14 @@ NKS_GenerateCookie(NKE_Key *c2s, NKE_Key *s2c, NKE_Cookie *cookie)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c2s->length < 0 || c2s->length > NKE_MAX_KEY_LENGTH ||
|
||||
s2c->length < 0 || s2c->length > NKE_MAX_KEY_LENGTH) {
|
||||
/* The algorithm is hardcoded for now */
|
||||
if (context->algorithm != AEAD_AES_SIV_CMAC_256) {
|
||||
DEBUG_LOG("Unexpected SIV algorithm");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (context->c2s.length < 0 || context->c2s.length > NKE_MAX_KEY_LENGTH ||
|
||||
context->s2c.length < 0 || context->s2c.length > NKE_MAX_KEY_LENGTH) {
|
||||
DEBUG_LOG("Invalid key length");
|
||||
return 0;
|
||||
}
|
||||
@@ -699,14 +768,13 @@ NKS_GenerateCookie(NKE_Key *c2s, NKE_Key *s2c, NKE_Cookie *cookie)
|
||||
|
||||
header = (ServerCookieHeader *)cookie->cookie;
|
||||
|
||||
/* Keep the fields in the host byte order */
|
||||
header->key_id = key->id;
|
||||
header->key_id = htonl(key->id);
|
||||
UTI_GetRandomBytes(header->nonce, sizeof (header->nonce));
|
||||
|
||||
plaintext_length = c2s->length + s2c->length;
|
||||
plaintext_length = context->c2s.length + context->s2c.length;
|
||||
assert(plaintext_length <= sizeof (plaintext));
|
||||
memcpy(plaintext, c2s->key, c2s->length);
|
||||
memcpy(plaintext + c2s->length, s2c->key, s2c->length);
|
||||
memcpy(plaintext, context->c2s.key, context->c2s.length);
|
||||
memcpy(plaintext + context->c2s.length, context->s2c.key, context->s2c.length);
|
||||
|
||||
tag_length = SIV_GetTagLength(key->siv);
|
||||
cookie->length = sizeof (*header) + plaintext_length + tag_length;
|
||||
@@ -727,12 +795,13 @@ NKS_GenerateCookie(NKE_Key *c2s, NKE_Key *s2c, NKE_Cookie *cookie)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Key *c2s, NKE_Key *s2c)
|
||||
NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Context *context)
|
||||
{
|
||||
unsigned char plaintext[2 * NKE_MAX_KEY_LENGTH], *ciphertext;
|
||||
int ciphertext_length, plaintext_length, tag_length;
|
||||
ServerCookieHeader *header;
|
||||
ServerKey *key;
|
||||
uint32_t key_id;
|
||||
|
||||
if (!initialised) {
|
||||
DEBUG_LOG("NTS server disabled");
|
||||
@@ -748,9 +817,10 @@ NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Key *c2s, NKE_Key *s2c)
|
||||
ciphertext = cookie->cookie + sizeof (*header);
|
||||
ciphertext_length = cookie->length - sizeof (*header);
|
||||
|
||||
key = &server_keys[header->key_id % MAX_SERVER_KEYS];
|
||||
if (header->key_id != key->id) {
|
||||
DEBUG_LOG("Unknown key %"PRIX32, header->key_id);
|
||||
key_id = ntohl(header->key_id);
|
||||
key = &server_keys[key_id % MAX_SERVER_KEYS];
|
||||
if (key_id != key->id) {
|
||||
DEBUG_LOG("Unknown key %"PRIX32, key_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -774,12 +844,14 @@ NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Key *c2s, NKE_Key *s2c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
c2s->length = plaintext_length / 2;
|
||||
s2c->length = plaintext_length / 2;
|
||||
assert(c2s->length <= sizeof (c2s->key));
|
||||
context->algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
|
||||
memcpy(c2s->key, plaintext, c2s->length);
|
||||
memcpy(s2c->key, plaintext + c2s->length, s2c->length);
|
||||
context->c2s.length = plaintext_length / 2;
|
||||
context->s2c.length = plaintext_length / 2;
|
||||
assert(context->c2s.length <= sizeof (context->c2s.key));
|
||||
|
||||
memcpy(context->c2s.key, plaintext, context->c2s.length);
|
||||
memcpy(context->s2c.key, plaintext + context->c2s.length, context->s2c.length);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,16 @@
|
||||
extern void NKS_Initialise(int scfilter_level);
|
||||
extern void NKS_Finalise(void);
|
||||
|
||||
/* Generate a new NTS cookie containing the C2S and S2C keys */
|
||||
extern int NKS_GenerateCookie(NKE_Key *c2s, NKE_Key *s2c, NKE_Cookie *cookie);
|
||||
/* Save the current server keys */
|
||||
extern void NKS_DumpKeys(void);
|
||||
|
||||
/* Validate a cookie and extract the C2S and S2C keys */
|
||||
extern int NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Key *c2s, NKE_Key *s2c);
|
||||
/* Reload the keys */
|
||||
extern void NKS_ReloadKeys(void);
|
||||
|
||||
/* Generate an NTS cookie with a given context */
|
||||
extern int NKS_GenerateCookie(NKE_Context *context, NKE_Cookie *cookie);
|
||||
|
||||
/* Validate a cookie and decode the context */
|
||||
extern int NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Context *context);
|
||||
|
||||
#endif
|
||||
|
||||
113
nts_ke_session.c
113
nts_ke_session.c
@@ -31,6 +31,7 @@
|
||||
#include "nts_ke_session.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "siv.h"
|
||||
@@ -39,6 +40,7 @@
|
||||
#include "util.h"
|
||||
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/x509.h>
|
||||
|
||||
#define INVALID_SOCK_FD (-8)
|
||||
|
||||
@@ -66,14 +68,16 @@ typedef enum {
|
||||
|
||||
struct NKSN_Instance_Record {
|
||||
int server;
|
||||
char *name;
|
||||
char *server_name;
|
||||
NKSN_MessageHandler handler;
|
||||
void *handler_arg;
|
||||
|
||||
KeState state;
|
||||
int sock_fd;
|
||||
char *label;
|
||||
gnutls_session_t tls_session;
|
||||
SCH_TimeoutID timeout_id;
|
||||
int retry_factor;
|
||||
|
||||
struct Message message;
|
||||
int new_message;
|
||||
@@ -86,6 +90,8 @@ static gnutls_priority_t priority_cache;
|
||||
|
||||
static int credentials_counter = 0;
|
||||
|
||||
static int clock_updates = 0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
@@ -206,6 +212,7 @@ create_tls_session(int server_mode, int sock_fd, const char *server_name,
|
||||
unsigned char alpn_name[sizeof (NKE_ALPN_NAME)];
|
||||
gnutls_session_t session;
|
||||
gnutls_datum_t alpn;
|
||||
unsigned int flags;
|
||||
int r;
|
||||
|
||||
r = gnutls_init(&session, GNUTLS_NONBLOCK | (server_mode ? GNUTLS_SERVER : GNUTLS_CLIENT));
|
||||
@@ -218,7 +225,15 @@ create_tls_session(int server_mode, int sock_fd, const char *server_name,
|
||||
r = gnutls_server_name_set(session, GNUTLS_NAME_DNS, server_name, strlen(server_name));
|
||||
if (r < 0)
|
||||
goto error;
|
||||
gnutls_session_set_verify_cert(session, server_name, 0);
|
||||
|
||||
flags = 0;
|
||||
|
||||
if (clock_updates < CNF_GetNoCertTimeCheck()) {
|
||||
flags |= GNUTLS_VERIFY_DISABLE_TIME_CHECKS | GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS;
|
||||
DEBUG_LOG("Disabled time checks");
|
||||
}
|
||||
|
||||
gnutls_session_set_verify_cert(session, server_name, flags);
|
||||
}
|
||||
|
||||
r = gnutls_priority_set(session, priority);
|
||||
@@ -261,6 +276,9 @@ stop_session(NKSN_Instance inst)
|
||||
SCK_CloseSocket(inst->sock_fd);
|
||||
inst->sock_fd = INVALID_SOCK_FD;
|
||||
|
||||
Free(inst->label);
|
||||
inst->label = NULL;
|
||||
|
||||
gnutls_deinit(inst->tls_session);
|
||||
inst->tls_session = NULL;
|
||||
|
||||
@@ -275,7 +293,7 @@ session_timeout(void *arg)
|
||||
{
|
||||
NKSN_Instance inst = arg;
|
||||
|
||||
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR, "NTS-KE session with %s timed out", inst->name);
|
||||
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR, "NTS-KE session with %s timed out", inst->label);
|
||||
|
||||
inst->timeout_id = 0;
|
||||
stop_session(inst);
|
||||
@@ -360,12 +378,12 @@ handle_event(NKSN_Instance inst, int event)
|
||||
r = get_socket_error(inst->sock_fd);
|
||||
|
||||
if (r) {
|
||||
LOG(LOGS_ERR, "Could not connect to %s : %s", inst->name, strerror(r));
|
||||
LOG(LOGS_ERR, "Could not connect to %s : %s", inst->label, strerror(r));
|
||||
stop_session(inst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Connected to %s", inst->name);
|
||||
DEBUG_LOG("Connected to %s", inst->label);
|
||||
|
||||
change_state(inst, KE_HANDSHAKE);
|
||||
return 0;
|
||||
@@ -376,8 +394,14 @@ handle_event(NKSN_Instance inst, int event)
|
||||
if (r < 0) {
|
||||
if (gnutls_error_is_fatal(r)) {
|
||||
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR,
|
||||
"TLS handshake with %s failed : %s", inst->name, gnutls_strerror(r));
|
||||
"TLS handshake with %s failed : %s", inst->label, gnutls_strerror(r));
|
||||
stop_session(inst);
|
||||
|
||||
/* Increase the retry interval if the handshake did not fail due
|
||||
to the other end closing the connection */
|
||||
if (r != GNUTLS_E_PULL_ERROR && r != GNUTLS_E_PREMATURE_TERMINATION)
|
||||
inst->retry_factor = NKE_RETRY_FACTOR2_TLS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -387,15 +411,17 @@ handle_event(NKSN_Instance inst, int event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
inst->retry_factor = NKE_RETRY_FACTOR2_TLS;
|
||||
|
||||
if (DEBUG) {
|
||||
char *description = gnutls_session_get_desc(inst->tls_session);
|
||||
DEBUG_LOG("Handshake with %s completed %s",
|
||||
inst->name, description ? description : "");
|
||||
inst->label, description ? description : "");
|
||||
gnutls_free(description);
|
||||
}
|
||||
|
||||
if (!check_alpn(inst)) {
|
||||
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR, "NTS-KE not supported by %s", inst->name);
|
||||
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR, "NTS-KE not supported by %s", inst->label);
|
||||
stop_session(inst);
|
||||
return 0;
|
||||
}
|
||||
@@ -413,13 +439,13 @@ handle_event(NKSN_Instance inst, int event)
|
||||
if (r < 0) {
|
||||
if (gnutls_error_is_fatal(r)) {
|
||||
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR,
|
||||
"Could not send NTS-KE message to %s : %s", inst->name, gnutls_strerror(r));
|
||||
"Could not send NTS-KE message to %s : %s", inst->label, gnutls_strerror(r));
|
||||
stop_session(inst);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Sent %d bytes to %s", r, inst->name);
|
||||
DEBUG_LOG("Sent %d bytes to %s", r, inst->label);
|
||||
|
||||
message->sent += r;
|
||||
if (message->sent < message->length)
|
||||
@@ -448,13 +474,13 @@ handle_event(NKSN_Instance inst, int event)
|
||||
if (gnutls_error_is_fatal(r) || r == GNUTLS_E_REHANDSHAKE) {
|
||||
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR,
|
||||
"Could not receive NTS-KE message from %s : %s",
|
||||
inst->name, gnutls_strerror(r));
|
||||
inst->label, gnutls_strerror(r));
|
||||
stop_session(inst);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Received %d bytes from %s", r, inst->name);
|
||||
DEBUG_LOG("Received %d bytes from %s", r, inst->label);
|
||||
|
||||
message->length += r;
|
||||
|
||||
@@ -462,7 +488,7 @@ handle_event(NKSN_Instance inst, int event)
|
||||
|
||||
if (!check_message_format(message, r == 0)) {
|
||||
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR,
|
||||
"Received invalid NTS-KE message from %s", inst->name);
|
||||
"Received invalid NTS-KE message from %s", inst->label);
|
||||
stop_session(inst);
|
||||
return 0;
|
||||
}
|
||||
@@ -480,7 +506,7 @@ handle_event(NKSN_Instance inst, int event)
|
||||
|
||||
if (r < 0) {
|
||||
if (gnutls_error_is_fatal(r)) {
|
||||
DEBUG_LOG("Shutdown with %s failed : %s", inst->name, gnutls_strerror(r));
|
||||
DEBUG_LOG("Shutdown with %s failed : %s", inst->label, gnutls_strerror(r));
|
||||
stop_session(inst);
|
||||
return 0;
|
||||
}
|
||||
@@ -524,6 +550,30 @@ read_write_socket(int fd, int event, void *arg)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static time_t
|
||||
get_time(time_t *t)
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
LCL_ReadCookedTime(&now, NULL);
|
||||
if (t)
|
||||
*t = now.tv_sec;
|
||||
|
||||
return now.tv_sec;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_step(struct timespec *raw, struct timespec *cooked, double dfreq,
|
||||
double doffset, LCL_ChangeType change_type, void *anything)
|
||||
{
|
||||
if (change_type != LCL_ChangeUnknownStep && clock_updates < INT_MAX)
|
||||
clock_updates++;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int gnutls_initialised = 0;
|
||||
|
||||
static void
|
||||
@@ -538,13 +588,18 @@ init_gnutls(void)
|
||||
if (r < 0)
|
||||
LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
|
||||
|
||||
/* NTS specification requires TLS1.2 or later */
|
||||
r = gnutls_priority_init2(&priority_cache, "-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1",
|
||||
/* 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",
|
||||
NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND);
|
||||
if (r < 0)
|
||||
LOG_FATAL("Could not initialise %s : %s", "priority cache", gnutls_strerror(r));
|
||||
|
||||
gnutls_global_set_time_function(get_time);
|
||||
|
||||
gnutls_initialised = 1;
|
||||
|
||||
LCL_AddParameterChangeHandler(handle_step, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -554,6 +609,8 @@ deinit_gnutls(void)
|
||||
{
|
||||
assert(gnutls_initialised);
|
||||
|
||||
LCL_RemoveParameterChangeHandler(handle_step, NULL);
|
||||
|
||||
gnutls_priority_deinit(priority_cache);
|
||||
gnutls_global_deinit();
|
||||
gnutls_initialised = 0;
|
||||
@@ -620,7 +677,7 @@ NKSN_DestroyCertCredentials(void *credentials)
|
||||
/* ================================================== */
|
||||
|
||||
NKSN_Instance
|
||||
NKSN_CreateInstance(int server_mode, const char *name,
|
||||
NKSN_CreateInstance(int server_mode, const char *server_name,
|
||||
NKSN_MessageHandler handler, void *handler_arg)
|
||||
{
|
||||
NKSN_Instance inst;
|
||||
@@ -628,7 +685,7 @@ NKSN_CreateInstance(int server_mode, const char *name,
|
||||
inst = MallocNew(struct NKSN_Instance_Record);
|
||||
|
||||
inst->server = server_mode;
|
||||
inst->name = Strdup(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 */
|
||||
@@ -637,8 +694,10 @@ NKSN_CreateInstance(int server_mode, const char *name,
|
||||
|
||||
inst->state = KE_STOPPED;
|
||||
inst->sock_fd = INVALID_SOCK_FD;
|
||||
inst->label = NULL;
|
||||
inst->tls_session = NULL;
|
||||
inst->timeout_id = 0;
|
||||
inst->retry_factor = NKE_RETRY_FACTOR2_CONNECT;
|
||||
|
||||
return inst;
|
||||
}
|
||||
@@ -650,19 +709,19 @@ NKSN_DestroyInstance(NKSN_Instance inst)
|
||||
{
|
||||
stop_session(inst);
|
||||
|
||||
Free(inst->name);
|
||||
Free(inst->server_name);
|
||||
Free(inst);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NKSN_StartSession(NKSN_Instance inst, int sock_fd, void *credentials, double timeout)
|
||||
NKSN_StartSession(NKSN_Instance inst, int sock_fd, const char *label,
|
||||
void *credentials, double timeout)
|
||||
{
|
||||
assert(inst->state == KE_STOPPED);
|
||||
|
||||
inst->tls_session = create_tls_session(inst->server, sock_fd,
|
||||
inst->server ? NULL : inst->name,
|
||||
inst->tls_session = create_tls_session(inst->server, sock_fd, inst->server_name,
|
||||
credentials, priority_cache);
|
||||
if (!inst->tls_session)
|
||||
return 0;
|
||||
@@ -670,7 +729,9 @@ NKSN_StartSession(NKSN_Instance inst, int sock_fd, void *credentials, double tim
|
||||
inst->sock_fd = sock_fd;
|
||||
SCH_AddFileHandler(sock_fd, SCH_FILE_INPUT, read_write_socket, inst);
|
||||
|
||||
inst->label = Strdup(label);
|
||||
inst->timeout_id = SCH_AddTimeoutByDelay(timeout, session_timeout, inst);
|
||||
inst->retry_factor = NKE_RETRY_FACTOR2_CONNECT;
|
||||
|
||||
reset_message(&inst->message);
|
||||
inst->new_message = 0;
|
||||
@@ -777,3 +838,11 @@ NKSN_StopSession(NKSN_Instance inst)
|
||||
{
|
||||
stop_session(inst);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NKSN_GetRetryFactor(NKSN_Instance inst)
|
||||
{
|
||||
return inst->retry_factor;
|
||||
}
|
||||
|
||||
@@ -45,15 +45,15 @@ extern void *NKSN_CreateCertCredentials(char *cert, char *key, char *trusted_cer
|
||||
extern void NKSN_DestroyCertCredentials(void *credentials);
|
||||
|
||||
/* Create an instance */
|
||||
extern NKSN_Instance NKSN_CreateInstance(int server_mode, const char *name,
|
||||
extern NKSN_Instance NKSN_CreateInstance(int server_mode, const char *server_name,
|
||||
NKSN_MessageHandler handler, void *handler_arg);
|
||||
|
||||
/* Destroy an instance */
|
||||
extern void NKSN_DestroyInstance(NKSN_Instance inst);
|
||||
|
||||
/* Start a new NTS-KE session */
|
||||
extern int NKSN_StartSession(NKSN_Instance inst, int sock_fd, void *credentials,
|
||||
double timeout);
|
||||
extern int NKSN_StartSession(NKSN_Instance inst, int sock_fd, const char *label,
|
||||
void *credentials, double timeout);
|
||||
|
||||
/* Begin an NTS-KE message. A request should be made right after starting
|
||||
the session and response should be made in the message handler. */
|
||||
@@ -80,4 +80,8 @@ extern int NKSN_IsStopped(NKSN_Instance inst);
|
||||
/* Stop the session */
|
||||
extern void NKSN_StopSession(NKSN_Instance inst);
|
||||
|
||||
/* Get a factor to calculate retry interval (in log2 seconds)
|
||||
based on the session state or how it was terminated */
|
||||
extern int NKSN_GetRetryFactor(NKSN_Instance inst);
|
||||
|
||||
#endif
|
||||
|
||||
284
nts_ntp_client.c
284
nts_ntp_client.c
@@ -44,18 +44,22 @@
|
||||
#include "util.h"
|
||||
|
||||
#define MAX_TOTAL_COOKIE_LENGTH (8 * 108)
|
||||
#define MIN_NKE_RETRY_INTERVAL 1000
|
||||
|
||||
#define DUMP_IDENTIFIER "NNC0\n"
|
||||
|
||||
struct NNC_Instance_Record {
|
||||
const IPSockAddr *ntp_address;
|
||||
IPSockAddr nts_address;
|
||||
char *name;
|
||||
SIV_Instance siv_c2s;
|
||||
SIV_Instance siv_s2c;
|
||||
NKC_Instance nke;
|
||||
SIV_Instance siv;
|
||||
|
||||
double last_nke_attempt;
|
||||
int load_attempt;
|
||||
int nke_attempts;
|
||||
double next_nke_attempt;
|
||||
double last_nke_success;
|
||||
|
||||
NKE_Context context;
|
||||
NKE_Cookie cookies[NTS_MAX_COOKIES];
|
||||
int num_cookies;
|
||||
int cookie_index;
|
||||
@@ -67,11 +71,20 @@ struct NNC_Instance_Record {
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void save_cookies(NNC_Instance inst);
|
||||
static void load_cookies(NNC_Instance inst);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
reset_instance(NNC_Instance inst)
|
||||
{
|
||||
inst->last_nke_attempt = -MIN_NKE_RETRY_INTERVAL;
|
||||
inst->load_attempt = 0;
|
||||
inst->nke_attempts = 0;
|
||||
inst->next_nke_attempt = 0.0;
|
||||
inst->last_nke_success = 0.0;
|
||||
|
||||
memset(&inst->context, 0, sizeof (inst->context));
|
||||
inst->num_cookies = 0;
|
||||
inst->cookie_index = 0;
|
||||
inst->nak_response = 0;
|
||||
@@ -92,8 +105,7 @@ NNC_CreateInstance(IPSockAddr *nts_address, const char *name, const IPSockAddr *
|
||||
inst->ntp_address = ntp_address;
|
||||
inst->nts_address = *nts_address;
|
||||
inst->name = name ? Strdup(name) : NULL;
|
||||
inst->siv_c2s = NULL;
|
||||
inst->siv_s2c = NULL;
|
||||
inst->siv = NULL;
|
||||
inst->nke = NULL;
|
||||
|
||||
reset_instance(inst);
|
||||
@@ -106,12 +118,12 @@ NNC_CreateInstance(IPSockAddr *nts_address, const char *name, const IPSockAddr *
|
||||
void
|
||||
NNC_DestroyInstance(NNC_Instance inst)
|
||||
{
|
||||
save_cookies(inst);
|
||||
|
||||
if (inst->nke)
|
||||
NKC_DestroyInstance(inst->nke);
|
||||
if (inst->siv_c2s)
|
||||
SIV_DestroyInstance(inst->siv_c2s);
|
||||
if (inst->siv_s2c)
|
||||
SIV_DestroyInstance(inst->siv_s2c);
|
||||
if (inst->siv)
|
||||
SIV_DestroyInstance(inst->siv);
|
||||
|
||||
Free(inst->name);
|
||||
Free(inst);
|
||||
@@ -120,7 +132,7 @@ NNC_DestroyInstance(NNC_Instance inst)
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
is_nke_needed(NNC_Instance inst)
|
||||
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) {
|
||||
@@ -133,7 +145,7 @@ is_nke_needed(NNC_Instance inst)
|
||||
SCH_GetLastEventMonoTime() - inst->last_nke_success > CNF_GetNtsRefresh())
|
||||
inst->num_cookies = 0;
|
||||
|
||||
return inst->num_cookies == 0;
|
||||
return inst->num_cookies > 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -167,22 +179,36 @@ set_ntp_address(NNC_Instance inst, NTP_Remote_Address *negotiated_address)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
update_next_nke_attempt(NNC_Instance inst, double now)
|
||||
{
|
||||
int factor, interval;
|
||||
|
||||
if (!inst->nke)
|
||||
return;
|
||||
|
||||
factor = NKC_GetRetryFactor(inst->nke);
|
||||
interval = MIN(factor + inst->nke_attempts - 1, NKE_MAX_RETRY_INTERVAL2);
|
||||
inst->next_nke_attempt = now + UTI_Log2ToDouble(interval);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
get_nke_data(NNC_Instance inst)
|
||||
get_cookies(NNC_Instance inst)
|
||||
{
|
||||
NTP_Remote_Address ntp_address;
|
||||
SIV_Algorithm siv;
|
||||
NKE_Key c2s, s2c;
|
||||
double now;
|
||||
int got_data;
|
||||
|
||||
assert(is_nke_needed(inst));
|
||||
assert(!check_cookies(inst));
|
||||
|
||||
now = SCH_GetLastEventMonoTime();
|
||||
|
||||
if (!inst->nke) {
|
||||
if (now - inst->last_nke_attempt < MIN_NKE_RETRY_INTERVAL) {
|
||||
DEBUG_LOG("Limiting NTS-KE request rate");
|
||||
if (now < inst->next_nke_attempt) {
|
||||
DEBUG_LOG("Limiting NTS-KE request rate (%f seconds)",
|
||||
inst->next_nke_attempt - now);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -194,25 +220,32 @@ get_nke_data(NNC_Instance inst)
|
||||
|
||||
inst->nke = NKC_CreateInstance(&inst->nts_address, inst->name);
|
||||
|
||||
inst->nke_attempts++;
|
||||
update_next_nke_attempt(inst, now);
|
||||
|
||||
if (!NKC_Start(inst->nke))
|
||||
return 0;
|
||||
|
||||
inst->last_nke_attempt = now;
|
||||
}
|
||||
|
||||
update_next_nke_attempt(inst, now);
|
||||
|
||||
if (NKC_IsActive(inst->nke))
|
||||
return 0;
|
||||
|
||||
got_data = NKC_GetNtsData(inst->nke, &siv, &c2s, &s2c,
|
||||
got_data = NKC_GetNtsData(inst->nke, &inst->context,
|
||||
inst->cookies, &inst->num_cookies, NTS_MAX_COOKIES,
|
||||
&ntp_address);
|
||||
|
||||
NKC_DestroyInstance(inst->nke);
|
||||
inst->nke = NULL;
|
||||
|
||||
|
||||
if (!got_data)
|
||||
return 0;
|
||||
|
||||
if (inst->siv)
|
||||
SIV_DestroyInstance(inst->siv);
|
||||
inst->siv = NULL;
|
||||
|
||||
if (!set_ntp_address(inst, &ntp_address)) {
|
||||
inst->num_cookies = 0;
|
||||
return 0;
|
||||
@@ -220,22 +253,6 @@ get_nke_data(NNC_Instance inst)
|
||||
|
||||
inst->cookie_index = 0;
|
||||
|
||||
if (inst->siv_c2s)
|
||||
SIV_DestroyInstance(inst->siv_c2s);
|
||||
if (inst->siv_s2c)
|
||||
SIV_DestroyInstance(inst->siv_s2c);
|
||||
|
||||
inst->siv_c2s = SIV_CreateInstance(siv);
|
||||
inst->siv_s2c = SIV_CreateInstance(siv);
|
||||
|
||||
if (!inst->siv_c2s || !inst->siv_s2c ||
|
||||
!SIV_SetKey(inst->siv_c2s, c2s.key, c2s.length) ||
|
||||
!SIV_SetKey(inst->siv_s2c, s2c.key, s2c.length)) {
|
||||
DEBUG_LOG("Could not initialise SIV");
|
||||
inst->num_cookies = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inst->nak_response = 0;
|
||||
|
||||
inst->last_nke_success = now;
|
||||
@@ -248,11 +265,25 @@ get_nke_data(NNC_Instance inst)
|
||||
int
|
||||
NNC_PrepareForAuth(NNC_Instance inst)
|
||||
{
|
||||
if (is_nke_needed(inst)) {
|
||||
if (!get_nke_data(inst))
|
||||
if (!inst->load_attempt) {
|
||||
load_cookies(inst);
|
||||
inst->load_attempt = 1;
|
||||
}
|
||||
|
||||
if (!check_cookies(inst)) {
|
||||
if (!get_cookies(inst))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!inst->siv)
|
||||
inst->siv = SIV_CreateInstance(inst->context.algorithm);
|
||||
|
||||
if (!inst->siv ||
|
||||
!SIV_SetKey(inst->siv, inst->context.c2s.key, inst->context.c2s.length)) {
|
||||
DEBUG_LOG("Could not set SIV key");
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_GetRandomBytes(&inst->uniq_id, sizeof (inst->uniq_id));
|
||||
UTI_GetRandomBytes(&inst->nonce, sizeof (inst->nonce));
|
||||
|
||||
@@ -267,8 +298,9 @@ NNC_GenerateRequestAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
{
|
||||
NKE_Cookie *cookie;
|
||||
int i, req_cookies;
|
||||
void *ef_body;
|
||||
|
||||
if (inst->num_cookies == 0 || !inst->siv_c2s)
|
||||
if (inst->num_cookies == 0 || !inst->siv)
|
||||
return 0;
|
||||
|
||||
if (info->mode != MODE_CLIENT)
|
||||
@@ -287,12 +319,13 @@ NNC_GenerateRequestAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < req_cookies - 1; i++) {
|
||||
if (!NEF_AddField(packet, info, NTP_EF_NTS_COOKIE_PLACEHOLDER,
|
||||
cookie->cookie, cookie->length))
|
||||
if (!NEF_AddBlankField(packet, info, NTP_EF_NTS_COOKIE_PLACEHOLDER,
|
||||
cookie->length, &ef_body))
|
||||
return 0;
|
||||
memset(ef_body, 0, cookie->length);
|
||||
}
|
||||
|
||||
if (!NNA_GenerateAuthEF(packet, info, inst->siv_c2s, inst->nonce, sizeof (inst->nonce),
|
||||
if (!NNA_GenerateAuthEF(packet, info, inst->siv, inst->nonce, sizeof (inst->nonce),
|
||||
(const unsigned char *)"", 0, NTP_MAX_V4_MAC_LENGTH + 4))
|
||||
return 0;
|
||||
|
||||
@@ -362,8 +395,11 @@ NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
if (inst->ok_response)
|
||||
return 0;
|
||||
|
||||
if (!inst->siv_s2c)
|
||||
if (!inst->siv ||
|
||||
!SIV_SetKey(inst->siv, inst->context.s2c.key, inst->context.s2c.length)) {
|
||||
DEBUG_LOG("Could not set SIV key");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (parsed = NTP_HEADER_LENGTH; parsed < info->length; parsed += ef_length) {
|
||||
if (!NEF_ParseField(packet, info->length, parsed,
|
||||
@@ -388,7 +424,7 @@ NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!NNA_DecryptAuthEF(packet, info, inst->siv_s2c, parsed,
|
||||
if (!NNA_DecryptAuthEF(packet, info, inst->siv, parsed,
|
||||
plaintext, sizeof (plaintext), &plaintext_length))
|
||||
return 0;
|
||||
|
||||
@@ -418,7 +454,8 @@ NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
|
||||
/* At this point we know the client interoperates with the server. Allow a
|
||||
new NTS-KE session to be started as soon as the cookies run out. */
|
||||
inst->last_nke_attempt = -MIN_NKE_RETRY_INTERVAL;
|
||||
inst->nke_attempts = 0;
|
||||
inst->next_nke_attempt = 0.0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -428,6 +465,8 @@ NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
void
|
||||
NNC_ChangeAddress(NNC_Instance inst, IPAddr *address)
|
||||
{
|
||||
save_cookies(inst);
|
||||
|
||||
if (inst->nke)
|
||||
NKC_DestroyInstance(inst->nke);
|
||||
|
||||
@@ -439,3 +478,152 @@ NNC_ChangeAddress(NNC_Instance inst, IPAddr *address)
|
||||
|
||||
DEBUG_LOG("NTS reset");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
save_cookies(NNC_Instance inst)
|
||||
{
|
||||
char buf[2 * NKE_MAX_COOKIE_LENGTH + 2], *dump_dir, *filename;
|
||||
struct timespec now;
|
||||
double context_time;
|
||||
FILE *f;
|
||||
int i;
|
||||
|
||||
if (inst->num_cookies < 1 || !UTI_IsIPReal(&inst->nts_address.ip_addr))
|
||||
return;
|
||||
|
||||
dump_dir = CNF_GetNtsDumpDir();
|
||||
if (!dump_dir)
|
||||
return;
|
||||
|
||||
filename = UTI_IPToString(&inst->nts_address.ip_addr);
|
||||
|
||||
f = UTI_OpenFile(dump_dir, filename, ".tmp", 'w', 0600);
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
SCH_GetLastEventTime(&now, NULL, NULL);
|
||||
context_time = inst->last_nke_success - SCH_GetLastEventMonoTime();
|
||||
context_time += UTI_TimespecToDouble(&now);
|
||||
|
||||
if (fprintf(f, "%s%.1f\n%s %d\n%d ",
|
||||
DUMP_IDENTIFIER, context_time, UTI_IPToString(&inst->ntp_address->ip_addr),
|
||||
inst->ntp_address->port, (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)) ||
|
||||
fprintf(f, "%s\n", buf) < 0)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < inst->num_cookies; i++) {
|
||||
if (!UTI_BytesToHex(inst->cookies[i].cookie, inst->cookies[i].length, buf, sizeof (buf)) ||
|
||||
fprintf(f, "%s\n", buf) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (!UTI_RenameTempFile(dump_dir, filename, ".tmp", ".nts"))
|
||||
;
|
||||
return;
|
||||
|
||||
error:
|
||||
DEBUG_LOG("Could not %s cookies for %s", "save", filename);
|
||||
fclose(f);
|
||||
|
||||
if (!UTI_RemoveFile(dump_dir, filename, ".nts"))
|
||||
;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define MAX_WORDS 3
|
||||
|
||||
static void
|
||||
load_cookies(NNC_Instance inst)
|
||||
{
|
||||
char line[2 * NKE_MAX_COOKIE_LENGTH + 2], *dump_dir, *filename, *words[MAX_WORDS];
|
||||
int i, algorithm, port;
|
||||
double context_time;
|
||||
struct timespec now;
|
||||
IPSockAddr ntp_addr;
|
||||
FILE *f;
|
||||
|
||||
dump_dir = CNF_GetNtsDumpDir();
|
||||
if (!dump_dir)
|
||||
return;
|
||||
|
||||
filename = UTI_IPToString(&inst->nts_address.ip_addr);
|
||||
|
||||
f = UTI_OpenFile(dump_dir, filename, ".nts", 'r', 0);
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
/* Don't load this file again */
|
||||
if (!UTI_RemoveFile(dump_dir, filename, ".nts"))
|
||||
;
|
||||
|
||||
if (inst->siv)
|
||||
SIV_DestroyInstance(inst->siv);
|
||||
inst->siv = NULL;
|
||||
|
||||
if (!fgets(line, sizeof (line), f) || strcmp(line, DUMP_IDENTIFIER) != 0 ||
|
||||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 1 ||
|
||||
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)
|
||||
goto error;
|
||||
|
||||
inst->context.algorithm = algorithm;
|
||||
inst->context.s2c.length = UTI_HexToBytes(words[1], inst->context.s2c.key,
|
||||
sizeof (inst->context.s2c.key));
|
||||
inst->context.c2s.length = UTI_HexToBytes(words[2], inst->context.c2s.key,
|
||||
sizeof (inst->context.c2s.key));
|
||||
|
||||
if (inst->context.s2c.length != SIV_GetKeyLength(algorithm) ||
|
||||
inst->context.c2s.length != inst->context.s2c.length)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < NTS_MAX_COOKIES && fgets(line, sizeof (line), f); i++) {
|
||||
if (UTI_SplitString(line, words, MAX_WORDS) != 1)
|
||||
goto error;
|
||||
|
||||
inst->cookies[i].length = UTI_HexToBytes(words[0], inst->cookies[i].cookie,
|
||||
sizeof (inst->cookies[i].cookie));
|
||||
if (inst->cookies[i].length == 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
inst->num_cookies = i;
|
||||
|
||||
ntp_addr.port = port;
|
||||
if (!set_ntp_address(inst, &ntp_addr))
|
||||
goto error;
|
||||
|
||||
SCH_GetLastEventTime(&now, NULL, NULL);
|
||||
context_time -= UTI_TimespecToDouble(&now);
|
||||
if (context_time > 0)
|
||||
context_time = 0;
|
||||
inst->last_nke_success = context_time + SCH_GetLastEventMonoTime();
|
||||
|
||||
DEBUG_LOG("Loaded %d cookies for %s", i, filename);
|
||||
return;
|
||||
|
||||
error:
|
||||
DEBUG_LOG("Could not %s cookies for %s", "load", filename);
|
||||
fclose(f);
|
||||
|
||||
memset(&inst->context, 0, sizeof (inst->context));
|
||||
inst->num_cookies = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NNC_DumpData(NNC_Instance inst)
|
||||
{
|
||||
save_cookies(inst);
|
||||
}
|
||||
|
||||
@@ -43,4 +43,6 @@ extern int NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
|
||||
extern void NNC_ChangeAddress(NNC_Instance inst, IPAddr *address);
|
||||
|
||||
extern void NNC_DumpData(NNC_Instance inst);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#include "siv.h"
|
||||
#include "util.h"
|
||||
|
||||
#define SERVER_SIV AEAD_AES_SIV_CMAC_256
|
||||
|
||||
struct NtsServer {
|
||||
SIV_Instance siv;
|
||||
unsigned char nonce[NTS_MIN_UNPADDED_NONCE_LENGTH];
|
||||
@@ -64,7 +66,7 @@ NNS_Initialise(void)
|
||||
}
|
||||
|
||||
server = Malloc(sizeof (struct NtsServer));
|
||||
server->siv = SIV_CreateInstance(AEAD_AES_SIV_CMAC_256);
|
||||
server->siv = SIV_CreateInstance(SERVER_SIV);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -88,8 +90,8 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
||||
int ef_type, ef_body_length, ef_length, has_uniq_id = 0, has_auth = 0, has_cookie = 0;
|
||||
int i, plaintext_length, parsed, requested_cookies, cookie_length = -1, auth_start = 0;
|
||||
unsigned char plaintext[NTP_MAX_EXTENSIONS_LENGTH];
|
||||
NKE_Context context;
|
||||
NKE_Cookie cookie;
|
||||
NKE_Key c2s, s2c;
|
||||
void *ef_body;
|
||||
|
||||
if (!server)
|
||||
@@ -144,12 +146,17 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!NKS_DecodeCookie(&cookie, &c2s, &s2c)) {
|
||||
if (!NKS_DecodeCookie(&cookie, &context)) {
|
||||
*kod = NTP_KOD_NTS_NAK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!SIV_SetKey(server->siv, c2s.key, c2s.length)) {
|
||||
if (context.algorithm != SERVER_SIV) {
|
||||
DEBUG_LOG("Unexpected SIV");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!SIV_SetKey(server->siv, context.c2s.key, context.c2s.length)) {
|
||||
DEBUG_LOG("Could not set C2S key");
|
||||
return 0;
|
||||
}
|
||||
@@ -178,7 +185,7 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
||||
}
|
||||
}
|
||||
|
||||
if (!SIV_SetKey(server->siv, s2c.key, s2c.length)) {
|
||||
if (!SIV_SetKey(server->siv, context.s2c.key, context.s2c.length)) {
|
||||
DEBUG_LOG("Could not set S2C key");
|
||||
return 0;
|
||||
}
|
||||
@@ -187,7 +194,7 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
|
||||
|
||||
server->num_cookies = MIN(NTS_MAX_COOKIES, requested_cookies);
|
||||
for (i = 0; i < server->num_cookies; i++)
|
||||
if (!NKS_GenerateCookie(&c2s, &s2c, &server->cookies[i]))
|
||||
if (!NKS_GenerateCookie(&context, &server->cookies[i]))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
16
privops.c
16
privops.c
@@ -171,22 +171,22 @@ send_response(int fd, const PrvResponse *res)
|
||||
static int
|
||||
receive_from_daemon(int fd, PrvRequest *req)
|
||||
{
|
||||
SCK_Message message;
|
||||
SCK_Message *message;
|
||||
|
||||
if (!SCK_ReceiveMessage(fd, &message, SCK_FLAG_MSG_DESCRIPTOR) ||
|
||||
message.length != sizeof (*req))
|
||||
message = SCK_ReceiveMessage(fd, SCK_FLAG_MSG_DESCRIPTOR);
|
||||
if (!message || message->length != sizeof (*req))
|
||||
return 0;
|
||||
|
||||
memcpy(req, message.data, sizeof (*req));
|
||||
memcpy(req, message->data, sizeof (*req));
|
||||
|
||||
if (req->op == OP_BINDSOCKET) {
|
||||
req->data.bind_socket.sock = message.descriptor;
|
||||
req->data.bind_socket.sock = message->descriptor;
|
||||
|
||||
/* return error if valid descriptor not found */
|
||||
if (req->data.bind_socket.sock < 0)
|
||||
return 0;
|
||||
} else if (message.descriptor >= 0) {
|
||||
SCK_CloseSocket(message.descriptor);
|
||||
} else if (message->descriptor >= 0) {
|
||||
SCK_CloseSocket(message->descriptor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -644,6 +644,8 @@ PRV_StartHelper(void)
|
||||
LOG_FATAL("Helper already running");
|
||||
|
||||
sock_fd1 = SCK_OpenUnixSocketPair(SCK_FLAG_BLOCK, &sock_fd2);
|
||||
if (sock_fd1 < 0)
|
||||
LOG_FATAL("Could not open socket pair");
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
|
||||
30
reference.c
30
reference.c
@@ -112,6 +112,9 @@ static void update_drift_file(double, double);
|
||||
/* Leap second handling mode */
|
||||
static REF_LeapMode leap_mode;
|
||||
|
||||
/* Time of UTC midnight of the upcoming or previous leap second */
|
||||
static time_t leap_when;
|
||||
|
||||
/* Flag indicating the clock was recently corrected for leap second and it may
|
||||
not have correct time yet (missing 23:59:60 in the UTC time scale) */
|
||||
static int leap_in_progress;
|
||||
@@ -246,6 +249,7 @@ REF_Initialise(void)
|
||||
enable_local_stratum = CNF_AllowLocalReference(&local_stratum, &local_orphan, &local_distance);
|
||||
UTI_ZeroTimespec(&local_ref_time);
|
||||
|
||||
leap_when = 0;
|
||||
leap_timeout_id = 0;
|
||||
leap_in_progress = 0;
|
||||
leap_mode = CNF_GetLeapSecMode();
|
||||
@@ -720,10 +724,12 @@ set_leap_timeout(time_t now)
|
||||
if (!our_leap_sec)
|
||||
return;
|
||||
|
||||
leap_when = (now / (24 * 3600) + 1) * (24 * 3600);
|
||||
|
||||
/* Insert leap second at 0:00:00 UTC, delete at 23:59:59 UTC. If the clock
|
||||
will be corrected by the system, timeout slightly sooner to be sure it
|
||||
will happen before the system correction. */
|
||||
when.tv_sec = (now / (24 * 3600) + 1) * (24 * 3600);
|
||||
when.tv_sec = leap_when;
|
||||
when.tv_nsec = 0;
|
||||
if (our_leap_sec < 0)
|
||||
when.tv_sec--;
|
||||
@@ -767,7 +773,7 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
}
|
||||
|
||||
if ((leap_sec != our_leap_sec || tai_offset != our_tai_offset)
|
||||
&& !REF_IsLeapSecondClose()) {
|
||||
&& !REF_IsLeapSecondClose(NULL, 0.0)) {
|
||||
our_leap_sec = leap_sec;
|
||||
our_tai_offset = tai_offset;
|
||||
|
||||
@@ -1324,22 +1330,24 @@ REF_DisableLocal(void)
|
||||
|
||||
#define LEAP_SECOND_CLOSE 5
|
||||
|
||||
int REF_IsLeapSecondClose(void)
|
||||
static int
|
||||
is_leap_close(time_t t)
|
||||
{
|
||||
return t >= leap_when - LEAP_SECOND_CLOSE && t < leap_when + LEAP_SECOND_CLOSE;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int REF_IsLeapSecondClose(struct timespec *ts, double offset)
|
||||
{
|
||||
struct timespec now, now_raw;
|
||||
time_t t;
|
||||
|
||||
if (!our_leap_sec)
|
||||
return 0;
|
||||
|
||||
SCH_GetLastEventTime(&now, NULL, &now_raw);
|
||||
|
||||
t = now.tv_sec > 0 ? now.tv_sec : -now.tv_sec;
|
||||
if ((t + LEAP_SECOND_CLOSE) % (24 * 3600) < 2 * LEAP_SECOND_CLOSE)
|
||||
if (is_leap_close(now.tv_sec) || is_leap_close(now_raw.tv_sec))
|
||||
return 1;
|
||||
|
||||
t = now_raw.tv_sec > 0 ? now_raw.tv_sec : -now_raw.tv_sec;
|
||||
if ((t + LEAP_SECOND_CLOSE) % (24 * 3600) < 2 * LEAP_SECOND_CLOSE)
|
||||
if (ts && (is_leap_close(ts->tv_sec) || is_leap_close(ts->tv_sec + offset)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -184,9 +184,9 @@ extern void REF_ModifyMakestep(int limit, double threshold);
|
||||
extern void REF_EnableLocal(int stratum, double distance, int orphan);
|
||||
extern void REF_DisableLocal(void);
|
||||
|
||||
/* Check if current raw or cooked time is close to a leap second
|
||||
and is better to discard any measurements */
|
||||
extern int REF_IsLeapSecondClose(void);
|
||||
/* Check if either of the current raw and cooked time, and optionally a
|
||||
provided timestamp with an offset, is close to a leap second */
|
||||
extern int REF_IsLeapSecondClose(struct timespec *ts, double offset);
|
||||
|
||||
/* Return TAI-UTC offset corresponding to a time in UTC if available */
|
||||
extern int REF_GetTaiOffset(struct timespec *ts);
|
||||
|
||||
@@ -267,7 +267,7 @@ select_samples(SPF_Instance filter)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = j = 0, k = -1; i < filter->used; i++) {
|
||||
for (i = j = 0; i < filter->used; i++) {
|
||||
if (selected[i] != -1)
|
||||
selected[j++] = (selected[i] + filter->used - o) % filter->used;
|
||||
}
|
||||
|
||||
51
socket.c
51
socket.c
@@ -68,7 +68,7 @@ struct Message {
|
||||
};
|
||||
|
||||
#ifdef HAVE_RECVMMSG
|
||||
#define MAX_RECV_MESSAGES SCK_MAX_RECV_MESSAGES
|
||||
#define MAX_RECV_MESSAGES 16
|
||||
#define MessageHeader mmsghdr
|
||||
#else
|
||||
/* Compatible with mmsghdr */
|
||||
@@ -85,9 +85,10 @@ static int initialised;
|
||||
/* Flags supported by socket() */
|
||||
static int supported_socket_flags;
|
||||
|
||||
/* Arrays of Message and MessageHeader */
|
||||
/* Arrays of Message, MessageHeader, and SCK_Message */
|
||||
static ARR_Instance recv_messages;
|
||||
static ARR_Instance recv_headers;
|
||||
static ARR_Instance recv_sck_messages;
|
||||
|
||||
static unsigned int received_messages;
|
||||
|
||||
@@ -342,6 +343,14 @@ bind_ip_address(int sock_fd, IPSockAddr *addr, int flags)
|
||||
if (addr->port > 0 && !SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1))
|
||||
;
|
||||
|
||||
#if defined(LINUX) && defined(SO_REUSEPORT)
|
||||
/* Allow multiple instances to bind to the same port in order to enable load
|
||||
balancing. Don't enable this option on non-Linux systems as it has
|
||||
a slightly different meaning there (with some important implications). */
|
||||
if (addr->port > 0 && !SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_REUSEPORT, 1))
|
||||
;
|
||||
#endif
|
||||
|
||||
#ifdef IP_FREEBIND
|
||||
/* Allow binding to an address that doesn't exist yet */
|
||||
if (!SCK_SetIntOption(sock_fd, IPPROTO_IP, IP_FREEBIND, 1))
|
||||
@@ -604,7 +613,7 @@ log_message(int sock_fd, int direction, SCK_Message *message, const char *prefix
|
||||
const char *local_addr, *remote_addr;
|
||||
char if_index[20], tss[10], tsif[20], tslen[20];
|
||||
|
||||
if (DEBUG <= 0 || log_min_severity < LOGS_DEBUG)
|
||||
if (DEBUG <= 0 || log_min_severity > LOGS_DEBUG)
|
||||
return;
|
||||
|
||||
remote_addr = NULL;
|
||||
@@ -859,22 +868,27 @@ process_header(struct msghdr *msg, unsigned int msg_length, int sock_fd, int fla
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
receive_messages(int sock_fd, SCK_Message *messages, int max_messages, int flags)
|
||||
static SCK_Message *
|
||||
receive_messages(int sock_fd, int flags, int max_messages, int *num_messages)
|
||||
{
|
||||
struct MessageHeader *hdr;
|
||||
SCK_Message *messages;
|
||||
unsigned int i, n;
|
||||
int ret, recv_flags = 0;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
*num_messages = 0;
|
||||
|
||||
if (max_messages < 1)
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
/* Prepare used buffers for new messages */
|
||||
prepare_buffers(received_messages);
|
||||
received_messages = 0;
|
||||
|
||||
messages = ARR_GetElements(recv_sck_messages);
|
||||
|
||||
hdr = ARR_GetElements(recv_headers);
|
||||
n = ARR_GetSize(recv_headers);
|
||||
n = MIN(n, max_messages);
|
||||
@@ -895,7 +909,7 @@ receive_messages(int sock_fd, SCK_Message *messages, int max_messages, int flags
|
||||
|
||||
if (ret < 0) {
|
||||
handle_recv_error(sock_fd, flags);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
received_messages = n;
|
||||
@@ -903,13 +917,15 @@ receive_messages(int sock_fd, SCK_Message *messages, int max_messages, int flags
|
||||
for (i = 0; i < n; i++) {
|
||||
hdr = ARR_GetElement(recv_headers, i);
|
||||
if (!process_header(&hdr->msg_hdr, hdr->msg_len, sock_fd, flags, &messages[i]))
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
log_message(sock_fd, 1, &messages[i],
|
||||
flags & SCK_FLAG_MSG_ERRQUEUE ? "Received error" : "Received", NULL);
|
||||
}
|
||||
|
||||
return n;
|
||||
*num_messages = n;
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1084,6 +1100,8 @@ SCK_Initialise(void)
|
||||
ARR_SetSize(recv_messages, MAX_RECV_MESSAGES);
|
||||
recv_headers = ARR_CreateInstance(sizeof (struct MessageHeader));
|
||||
ARR_SetSize(recv_headers, MAX_RECV_MESSAGES);
|
||||
recv_sck_messages = ARR_CreateInstance(sizeof (SCK_Message));
|
||||
ARR_SetSize(recv_sck_messages, MAX_RECV_MESSAGES);
|
||||
|
||||
received_messages = MAX_RECV_MESSAGES;
|
||||
|
||||
@@ -1107,6 +1125,7 @@ SCK_Initialise(void)
|
||||
void
|
||||
SCK_Finalise(void)
|
||||
{
|
||||
ARR_DestroyInstance(recv_sck_messages);
|
||||
ARR_DestroyInstance(recv_headers);
|
||||
ARR_DestroyInstance(recv_messages);
|
||||
|
||||
@@ -1373,18 +1392,20 @@ SCK_Send(int sock_fd, const void *buffer, unsigned int length, int flags)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SCK_ReceiveMessage(int sock_fd, SCK_Message *message, int flags)
|
||||
SCK_Message *
|
||||
SCK_ReceiveMessage(int sock_fd, int flags)
|
||||
{
|
||||
return SCK_ReceiveMessages(sock_fd, message, 1, flags);
|
||||
int num_messages;
|
||||
|
||||
return receive_messages(sock_fd, flags, 1, &num_messages);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SCK_ReceiveMessages(int sock_fd, SCK_Message *messages, int max_messages, int flags)
|
||||
SCK_Message *
|
||||
SCK_ReceiveMessages(int sock_fd, int flags, int *num_messages)
|
||||
{
|
||||
return receive_messages(sock_fd, messages, max_messages, flags);
|
||||
return receive_messages(sock_fd, flags, MAX_RECV_MESSAGES, num_messages);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
14
socket.h
14
socket.h
@@ -41,9 +41,6 @@
|
||||
#define SCK_FLAG_MSG_ERRQUEUE 1
|
||||
#define SCK_FLAG_MSG_DESCRIPTOR 2
|
||||
|
||||
/* Maximum number of received messages */
|
||||
#define SCK_MAX_RECV_MESSAGES 4
|
||||
|
||||
typedef enum {
|
||||
SCK_ADDR_UNSPEC = 0,
|
||||
SCK_ADDR_IP,
|
||||
@@ -119,12 +116,11 @@ extern int SCK_ShutdownConnection(int sock_fd);
|
||||
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);
|
||||
|
||||
/* Receive a single message or multiple messages. The functions return the
|
||||
number of received messages, or 0 on error. The returned data point to
|
||||
static buffers, which are valid until another call of these functions. */
|
||||
extern int SCK_ReceiveMessage(int sock_fd, SCK_Message *message, int flags);
|
||||
extern int SCK_ReceiveMessages(int sock_fd, SCK_Message *messages, int max_messages,
|
||||
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
|
||||
another call of the functions and can be reused for sending messages. */
|
||||
extern SCK_Message *SCK_ReceiveMessage(int sock_fd, int flags);
|
||||
extern SCK_Message *SCK_ReceiveMessages(int sock_fd, int flags, int *num_messages);
|
||||
|
||||
/* Initialise a new message (e.g. before sending) */
|
||||
extern void SCK_InitMessage(SCK_Message *message, SCK_AddressType addr_type);
|
||||
|
||||
@@ -361,7 +361,7 @@ get_leap_status(void)
|
||||
void
|
||||
SRC_SetLeapStatus(SRC_Instance inst, NTP_Leap leap)
|
||||
{
|
||||
if (REF_IsLeapSecondClose())
|
||||
if (REF_IsLeapSecondClose(NULL, 0.0))
|
||||
return;
|
||||
|
||||
inst->leap = leap;
|
||||
@@ -390,7 +390,7 @@ SRC_AccumulateSample(SRC_Instance inst, NTP_Sample *sample)
|
||||
source_to_string(inst), UTI_TimespecToString(&sample->time), -sample->offset,
|
||||
sample->root_delay, sample->root_dispersion, sample->stratum);
|
||||
|
||||
if (REF_IsLeapSecondClose()) {
|
||||
if (REF_IsLeapSecondClose(&sample->time, sample->offset)) {
|
||||
LOG(LOGS_INFO, "Dropping sample around leap second");
|
||||
return;
|
||||
}
|
||||
@@ -483,7 +483,7 @@ SRC_ResetReachability(SRC_Instance inst)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
log_selection_message(char *format, char *arg)
|
||||
log_selection_message(const char *format, const char *arg)
|
||||
{
|
||||
if (REF_GetMode() != REF_ModeNormal)
|
||||
return;
|
||||
@@ -1197,7 +1197,6 @@ FILE *open_dumpfile(SRC_Instance inst, char mode)
|
||||
|
||||
dumpdir = CNF_GetDumpDir();
|
||||
if (dumpdir[0] == '\0') {
|
||||
LOG(LOGS_WARN, "dumpdir not specified");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
20
stubs.c
20
stubs.c
@@ -331,6 +331,11 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
|
||||
memset(report, 0, sizeof (*report));
|
||||
}
|
||||
|
||||
void
|
||||
NSR_DumpAuthData(void)
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef FEAT_CMDMON
|
||||
|
||||
void
|
||||
@@ -515,6 +520,11 @@ NNC_ChangeAddress(NNC_Instance inst, IPAddr *address)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NNC_DumpData(NNC_Instance inst)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NKC_Initialise(void)
|
||||
{
|
||||
@@ -535,4 +545,14 @@ NKS_Finalise(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NKS_DumpKeys(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NKS_ReloadKeys(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !FEAT_NTS */
|
||||
|
||||
@@ -523,6 +523,9 @@ SYS_Linux_EnableSystemCallFilter(int level, SYS_SystemCallContext context)
|
||||
{ SOL_IPV6, IPV6_V6ONLY }, { SOL_IPV6, IPV6_RECVPKTINFO },
|
||||
#endif
|
||||
{ SOL_SOCKET, SO_BROADCAST }, { SOL_SOCKET, SO_REUSEADDR },
|
||||
#ifdef SO_REUSEPORT
|
||||
{ SOL_SOCKET, SO_REUSEPORT },
|
||||
#endif
|
||||
{ SOL_SOCKET, SO_TIMESTAMP }, { SOL_SOCKET, SO_TIMESTAMPNS },
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
{ SOL_SOCKET, SO_SELECT_ERR_QUEUE }, { SOL_SOCKET, SO_TIMESTAMPING },
|
||||
|
||||
@@ -46,8 +46,9 @@
|
||||
#include "privops.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef HAVE_MACOS_SYS_TIMEX
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifdef HAVE_MACOS_SYS_TIMEX
|
||||
#include "sys_netbsd.h"
|
||||
|
||||
static int have_ntp_adjtime = 0;
|
||||
|
||||
@@ -29,7 +29,8 @@ server_conf="
|
||||
ntsserverkey tmp/server.key
|
||||
ntsservercert tmp/server.crt
|
||||
ntsprocesses 0
|
||||
ntsrotate 64
|
||||
ntsrotate 66
|
||||
ntsdumpdir tmp
|
||||
"
|
||||
client_server_options="minpoll 6 maxpoll 6 nts"
|
||||
client_conf="
|
||||
@@ -43,27 +44,57 @@ check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
check_file_messages "20.*123\.1.* 111 111 1111" 91 93 measurements.log || test_fail
|
||||
check_file_messages "20.*123\.1.* 111 001 0000" 30 32 measurements.log || 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 "." 6 6 ntskeys || test_fail
|
||||
rm -f tmp/measurements.log
|
||||
|
||||
client_conf+="
|
||||
ntsrefresh 120"
|
||||
ntsrefresh 120
|
||||
ntsdumpdir tmp"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
check_file_messages "20.*123\.1.* 111 111 1111" 101 103 measurements.log || 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 "." 6 6 ntskeys || test_fail
|
||||
check_file_messages "." 11 12 192.168.123.1.nts || test_fail
|
||||
rm -f tmp/measurements.log
|
||||
|
||||
client_conf=""
|
||||
export CLKNETSIM_START_DATE=$(date -d 'Jan 1 00:00:00 UTC 2010 + 40000 sec' +'%s')
|
||||
|
||||
server_conf+="
|
||||
ntsrotate 100000"
|
||||
client_conf+="
|
||||
ntsrefresh 39500"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
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 "." 6 6 ntskeys || test_fail
|
||||
check_file_messages "." 11 12 192.168.123.1.nts || test_fail
|
||||
rm -f tmp/measurements.log
|
||||
|
||||
client_conf="
|
||||
nosystemcert"
|
||||
|
||||
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 .* 11443 " 10 20 log.packets || test_fail
|
||||
|
||||
test_pass
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#ifdef FEAT_NTS
|
||||
|
||||
#include <nts_ke_client.c>
|
||||
#include <local.h>
|
||||
|
||||
static void
|
||||
prepare_response(NKSN_Instance session, int valid)
|
||||
@@ -110,6 +111,7 @@ test_unit(void)
|
||||
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
|
||||
CNF_ParseLine(NULL, i + 1, conf[i]);
|
||||
|
||||
LCL_Initialise();
|
||||
NKC_Initialise();
|
||||
|
||||
SCK_GetLoopbackIPAddress(AF_INET, &addr.ip_addr);
|
||||
@@ -128,6 +130,7 @@ test_unit(void)
|
||||
NKC_DestroyInstance(inst);
|
||||
|
||||
NKC_Finalise();
|
||||
LCL_Finalise();
|
||||
CNF_Finalise();
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -132,13 +132,13 @@ void
|
||||
test_unit(void)
|
||||
{
|
||||
NKSN_Instance session;
|
||||
NKE_Context context, context2;
|
||||
NKE_Cookie cookie;
|
||||
NKE_Key c2s, s2c, c2s2, s2c2;
|
||||
int i, valid, l;
|
||||
uint32_t sum, sum2;
|
||||
|
||||
char conf[][100] = {
|
||||
"ntscachedir .",
|
||||
"ntsdumpdir .",
|
||||
"ntsport 0",
|
||||
"ntsprocesses 0",
|
||||
"ntsserverkey nts_ke.key",
|
||||
@@ -156,7 +156,7 @@ test_unit(void)
|
||||
unlink("ntskeys");
|
||||
NKS_Initialise(0);
|
||||
|
||||
session = NKSN_CreateInstance(1, "", handle_message, NULL);
|
||||
session = NKSN_CreateInstance(1, NULL, handle_message, NULL);
|
||||
|
||||
for (i = 0; i < 10000; i++) {
|
||||
valid = random() % 2;
|
||||
@@ -167,14 +167,16 @@ test_unit(void)
|
||||
|
||||
|
||||
for (i = 0; i < 10000; i++) {
|
||||
get_keys(session, AEAD_AES_SIV_CMAC_256, &c2s, &s2c);
|
||||
context.algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
get_keys(session, context.algorithm, &context.c2s, &context.s2c);
|
||||
memset(&cookie, 0, sizeof (cookie));
|
||||
TEST_CHECK(NKS_GenerateCookie(&c2s, &s2c, &cookie));
|
||||
TEST_CHECK(NKS_DecodeCookie(&cookie, &c2s2, &s2c2));
|
||||
TEST_CHECK(c2s.length == c2s2.length);
|
||||
TEST_CHECK(s2c.length == s2c2.length);
|
||||
TEST_CHECK(memcmp(c2s.key, c2s2.key, c2s.length) == 0);
|
||||
TEST_CHECK(memcmp(s2c.key, s2c2.key, s2c.length) == 0);
|
||||
TEST_CHECK(NKS_GenerateCookie(&context, &cookie));
|
||||
TEST_CHECK(NKS_DecodeCookie(&cookie, &context2));
|
||||
TEST_CHECK(context.algorithm == context2.algorithm);
|
||||
TEST_CHECK(context.c2s.length == context2.c2s.length);
|
||||
TEST_CHECK(context.s2c.length == context2.s2c.length);
|
||||
TEST_CHECK(memcmp(context.c2s.key, context2.c2s.key, context.c2s.length) == 0);
|
||||
TEST_CHECK(memcmp(context.s2c.key, context2.s2c.key, context.s2c.length) == 0);
|
||||
|
||||
if (random() % 4) {
|
||||
cookie.cookie[random() % (cookie.length)]++;
|
||||
@@ -185,7 +187,7 @@ test_unit(void)
|
||||
while (l == cookie.length)
|
||||
cookie.length = random() % (sizeof (cookie.cookie) + 1);
|
||||
}
|
||||
TEST_CHECK(!NKS_DecodeCookie(&cookie, &c2s2, &s2c2));
|
||||
TEST_CHECK(!NKS_DecodeCookie(&cookie, &context2));
|
||||
}
|
||||
|
||||
unlink("ntskeys");
|
||||
|
||||
@@ -142,7 +142,7 @@ test_unit(void)
|
||||
for (i = 0; i < 50; i++) {
|
||||
SCH_Initialise();
|
||||
|
||||
server = NKSN_CreateInstance(1, "client", handle_request, NULL);
|
||||
server = NKSN_CreateInstance(1, NULL, handle_request, NULL);
|
||||
client = NKSN_CreateInstance(0, "test", handle_response, NULL);
|
||||
|
||||
server_cred = NKSN_CreateCertCredentials("nts_ke.crt", "nts_ke.key", NULL);
|
||||
@@ -152,8 +152,8 @@ test_unit(void)
|
||||
TEST_CHECK(fcntl(sock_fds[0], F_SETFL, O_NONBLOCK) == 0);
|
||||
TEST_CHECK(fcntl(sock_fds[1], F_SETFL, O_NONBLOCK) == 0);
|
||||
|
||||
TEST_CHECK(NKSN_StartSession(server, sock_fds[0], server_cred, 4.0));
|
||||
TEST_CHECK(NKSN_StartSession(client, sock_fds[1], client_cred, 4.0));
|
||||
TEST_CHECK(NKSN_StartSession(server, sock_fds[0], "client", server_cred, 4.0));
|
||||
TEST_CHECK(NKSN_StartSession(client, sock_fds[1], "server", client_cred, 4.0));
|
||||
|
||||
send_message(client);
|
||||
|
||||
|
||||
@@ -32,27 +32,29 @@
|
||||
#define NKC_Start(inst) (random() % 2)
|
||||
#define NKC_IsActive(inst) (random() % 2)
|
||||
|
||||
static int get_nts_data(NKC_Instance inst, SIV_Algorithm *siv_algorithm, NKE_Key *c2s, NKE_Key *s2c,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies, IPSockAddr *ntp_address);
|
||||
static int get_nts_data(NKC_Instance inst, NKE_Context *context,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
|
||||
IPSockAddr *ntp_address);
|
||||
#define NKC_GetNtsData get_nts_data
|
||||
|
||||
#include <nts_ntp_client.c>
|
||||
|
||||
static int
|
||||
get_nts_data(NKC_Instance inst, SIV_Algorithm *siv_algorithm, NKE_Key *c2s, NKE_Key *s2c,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies, IPSockAddr *ntp_address)
|
||||
get_nts_data(NKC_Instance inst, NKE_Context *context,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
|
||||
IPSockAddr *ntp_address)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (random() % 2)
|
||||
return 0;
|
||||
|
||||
*siv_algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
context->algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
|
||||
c2s->length = SIV_GetKeyLength(*siv_algorithm);
|
||||
UTI_GetRandomBytes(c2s->key, c2s->length);
|
||||
s2c->length = SIV_GetKeyLength(*siv_algorithm);
|
||||
UTI_GetRandomBytes(s2c->key, s2c->length);
|
||||
context->c2s.length = SIV_GetKeyLength(context->algorithm);
|
||||
UTI_GetRandomBytes(context->c2s.key, context->c2s.length);
|
||||
context->s2c.length = SIV_GetKeyLength(context->algorithm);
|
||||
UTI_GetRandomBytes(context->s2c.key, context->s2c.length);
|
||||
|
||||
*num_cookies = random() % max_cookies + 1;
|
||||
for (i = 0; i < *num_cookies; i++) {
|
||||
@@ -85,12 +87,11 @@ get_request(NNC_Instance inst)
|
||||
TEST_CHECK(!NNC_GenerateRequestAuth(inst, &packet, &info));
|
||||
|
||||
while (!NNC_PrepareForAuth(inst)) {
|
||||
inst->last_nke_attempt = random() % 100000 - 50000;
|
||||
inst->next_nke_attempt = SCH_GetLastEventMonoTime() + random() % 10 - 7;
|
||||
}
|
||||
|
||||
TEST_CHECK(inst->num_cookies > 0);
|
||||
TEST_CHECK(inst->siv_c2s);
|
||||
TEST_CHECK(inst->siv_s2c);
|
||||
TEST_CHECK(inst->siv);
|
||||
|
||||
memcpy(nonce, inst->nonce, sizeof (nonce));
|
||||
memcpy(uniq_id, inst->uniq_id, sizeof (uniq_id));
|
||||
@@ -103,7 +104,7 @@ get_request(NNC_Instance inst)
|
||||
(inst->cookies[inst->cookie_index].length + 4));
|
||||
expected_length = info.length + 4 + sizeof (inst->uniq_id) +
|
||||
req_cookies * (4 + inst->cookies[inst->cookie_index].length) +
|
||||
4 + 4 + sizeof (inst->nonce) + SIV_GetTagLength(inst->siv_c2s);
|
||||
4 + 4 + sizeof (inst->nonce) + SIV_GetTagLength(inst->siv);
|
||||
DEBUG_LOG("length=%d cookie_length=%d expected_length=%d",
|
||||
info.length, inst->cookies[inst->cookie_index].length, expected_length);
|
||||
|
||||
@@ -126,6 +127,7 @@ prepare_response(NNC_Instance inst, NTP_Packet *packet, NTP_PacketInfo *info, in
|
||||
unsigned char cookie[508], plaintext[512], nonce[512];
|
||||
int nonce_length, cookie_length, plaintext_length, min_auth_length;
|
||||
int index, auth_start;
|
||||
SIV_Instance siv;
|
||||
|
||||
memset(packet, 0, sizeof (*packet));
|
||||
packet->lvm = NTP_LVM(0, 4, MODE_SERVER);
|
||||
@@ -175,10 +177,15 @@ prepare_response(NNC_Instance inst, NTP_Packet *packet, NTP_PacketInfo *info, in
|
||||
TEST_CHECK(NEF_SetField(plaintext, sizeof (plaintext), 0, NTP_EF_NTS_COOKIE,
|
||||
cookie, cookie_length, &plaintext_length));
|
||||
auth_start = info->length;
|
||||
if (index != 4)
|
||||
TEST_CHECK(NNA_GenerateAuthEF(packet, info, inst->siv_s2c,
|
||||
if (index != 4) {
|
||||
siv = SIV_CreateInstance(inst->context.algorithm);
|
||||
TEST_CHECK(siv);
|
||||
TEST_CHECK(SIV_SetKey(siv, inst->context.s2c.key, inst->context.s2c.length));
|
||||
TEST_CHECK(NNA_GenerateAuthEF(packet, info, siv,
|
||||
nonce, nonce_length, plaintext, plaintext_length,
|
||||
min_auth_length));
|
||||
SIV_DestroyInstance(siv);
|
||||
}
|
||||
if (index == 5)
|
||||
((unsigned char *)packet)[auth_start + 8]++;
|
||||
}
|
||||
|
||||
@@ -32,17 +32,18 @@ static void
|
||||
prepare_request(NTP_Packet *packet, NTP_PacketInfo *info, int valid, int nak)
|
||||
{
|
||||
unsigned char uniq_id[NTS_MIN_UNIQ_ID_LENGTH], nonce[NTS_MIN_UNPADDED_NONCE_LENGTH];
|
||||
NKE_Key c2s, s2c;
|
||||
SIV_Instance siv;
|
||||
NKE_Context context;
|
||||
NKE_Cookie cookie;
|
||||
int i, index, cookie_start, auth_start;
|
||||
|
||||
c2s.length = SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256);
|
||||
UTI_GetRandomBytes(&c2s.key, c2s.length);
|
||||
s2c.length = SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256);
|
||||
UTI_GetRandomBytes(&s2c.key, s2c.length);
|
||||
context.algorithm = SERVER_SIV;
|
||||
context.c2s.length = SIV_GetKeyLength(context.algorithm);
|
||||
UTI_GetRandomBytes(&context.c2s.key, context.c2s.length);
|
||||
context.s2c.length = SIV_GetKeyLength(context.algorithm);
|
||||
UTI_GetRandomBytes(&context.s2c.key, context.s2c.length);
|
||||
|
||||
TEST_CHECK(NKS_GenerateCookie(&c2s, &s2c, &cookie));
|
||||
TEST_CHECK(NKS_GenerateCookie(&context, &cookie));
|
||||
|
||||
UTI_GetRandomBytes(uniq_id, sizeof (uniq_id));
|
||||
UTI_GetRandomBytes(nonce, sizeof (nonce));
|
||||
@@ -78,8 +79,8 @@ prepare_request(NTP_Packet *packet, NTP_PacketInfo *info, int valid, int nak)
|
||||
auth_start = info->length;
|
||||
|
||||
if (index != 2) {
|
||||
siv = SIV_CreateInstance(AEAD_AES_SIV_CMAC_256);
|
||||
TEST_CHECK(SIV_SetKey(siv, c2s.key, c2s.length));
|
||||
siv = SIV_CreateInstance(context.algorithm);
|
||||
TEST_CHECK(SIV_SetKey(siv, context.c2s.key, context.c2s.length));
|
||||
TEST_CHECK(NNA_GenerateAuthEF(packet, info, siv, nonce, sizeof (nonce),
|
||||
(const unsigned char *)"", 0, 0));
|
||||
SIV_DestroyInstance(siv);
|
||||
|
||||
@@ -30,7 +30,7 @@ void test_unit(void) {
|
||||
Timespec tspec;
|
||||
Float f;
|
||||
int i, j, c;
|
||||
char buf[16], *s;
|
||||
char buf[16], *s, *words[3];
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
struct stat st;
|
||||
@@ -333,4 +333,37 @@ void test_unit(void) {
|
||||
TEST_CHECK(UTI_BytesToHex("\xAB\x12\x34\x56\x78\x00\x01", 7, buf, 14) == 0);
|
||||
TEST_CHECK(UTI_BytesToHex("\xAB\x12\x34\x56\x78\x00\x01", 7, buf, 15) == 1);
|
||||
TEST_CHECK(strcmp(buf, "AB123456780001") == 0);
|
||||
|
||||
TEST_CHECK(snprintf(buf, sizeof (buf), "%s", "") < sizeof (buf));
|
||||
TEST_CHECK(UTI_SplitString(buf, words, 3) == 0);
|
||||
TEST_CHECK(!words[0]);
|
||||
TEST_CHECK(snprintf(buf, sizeof (buf), "%s", " ") < sizeof (buf));
|
||||
TEST_CHECK(UTI_SplitString(buf, words, 3) == 0);
|
||||
TEST_CHECK(!words[0]);
|
||||
TEST_CHECK(snprintf(buf, sizeof (buf), "%s", "a \n ") < sizeof (buf));
|
||||
TEST_CHECK(UTI_SplitString(buf, words, 3) == 1);
|
||||
TEST_CHECK(words[0] == buf + 0);
|
||||
TEST_CHECK(strcmp(words[0], "a") == 0);
|
||||
TEST_CHECK(snprintf(buf, sizeof (buf), "%s", " a ") < sizeof (buf));
|
||||
TEST_CHECK(UTI_SplitString(buf, words, 3) == 1);
|
||||
TEST_CHECK(words[0] == buf + 2);
|
||||
TEST_CHECK(strcmp(words[0], "a") == 0);
|
||||
TEST_CHECK(snprintf(buf, sizeof (buf), "%s", " \n a") < sizeof (buf));
|
||||
TEST_CHECK(UTI_SplitString(buf, words, 3) == 1);
|
||||
TEST_CHECK(words[0] == buf + 4);
|
||||
TEST_CHECK(strcmp(words[0], "a") == 0);
|
||||
TEST_CHECK(snprintf(buf, sizeof (buf), "%s", "a b") < sizeof (buf));
|
||||
TEST_CHECK(UTI_SplitString(buf, words, 1) == 2);
|
||||
TEST_CHECK(snprintf(buf, sizeof (buf), "%s", "a b") < sizeof (buf));
|
||||
TEST_CHECK(UTI_SplitString(buf, words, 2) == 2);
|
||||
TEST_CHECK(words[0] == buf + 0);
|
||||
TEST_CHECK(words[1] == buf + 4);
|
||||
TEST_CHECK(strcmp(words[0], "a") == 0);
|
||||
TEST_CHECK(strcmp(words[1], "b") == 0);
|
||||
TEST_CHECK(snprintf(buf, sizeof (buf), "%s", " a b ") < sizeof (buf));
|
||||
TEST_CHECK(UTI_SplitString(buf, words, 3) == 2);
|
||||
TEST_CHECK(words[0] == buf + 1);
|
||||
TEST_CHECK(words[1] == buf + 3);
|
||||
TEST_CHECK(strcmp(words[0], "a") == 0);
|
||||
TEST_CHECK(strcmp(words[1], "b") == 0);
|
||||
}
|
||||
|
||||
96
util.c
96
util.c
@@ -56,7 +56,7 @@ UTI_IsZeroTimespec(struct timespec *ts)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_TimevalToTimespec(struct timeval *tv, struct timespec *ts)
|
||||
UTI_TimevalToTimespec(const struct timeval *tv, struct timespec *ts)
|
||||
{
|
||||
ts->tv_sec = tv->tv_sec;
|
||||
ts->tv_nsec = 1000 * tv->tv_usec;
|
||||
@@ -65,7 +65,7 @@ UTI_TimevalToTimespec(struct timeval *tv, struct timespec *ts)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_TimespecToTimeval(struct timespec *ts, struct timeval *tv)
|
||||
UTI_TimespecToTimeval(const struct timespec *ts, struct timeval *tv)
|
||||
{
|
||||
tv->tv_sec = ts->tv_sec;
|
||||
tv->tv_usec = ts->tv_nsec / 1000;
|
||||
@@ -74,7 +74,7 @@ UTI_TimespecToTimeval(struct timespec *ts, struct timeval *tv)
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
UTI_TimespecToDouble(struct timespec *ts)
|
||||
UTI_TimespecToDouble(const struct timespec *ts)
|
||||
{
|
||||
return ts->tv_sec + 1.0e-9 * ts->tv_nsec;
|
||||
}
|
||||
@@ -109,7 +109,7 @@ UTI_NormaliseTimespec(struct timespec *ts)
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
UTI_TimevalToDouble(struct timeval *tv)
|
||||
UTI_TimevalToDouble(const struct timeval *tv)
|
||||
{
|
||||
return tv->tv_sec + 1.0e-6 * tv->tv_usec;
|
||||
}
|
||||
@@ -149,7 +149,7 @@ UTI_NormaliseTimeval(struct timeval *x)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
UTI_CompareTimespecs(struct timespec *a, struct timespec *b)
|
||||
UTI_CompareTimespecs(const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
if (a->tv_sec < b->tv_sec)
|
||||
return -1;
|
||||
@@ -165,7 +165,7 @@ UTI_CompareTimespecs(struct timespec *a, struct timespec *b)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_DiffTimespecs(struct timespec *result, struct timespec *a, struct timespec *b)
|
||||
UTI_DiffTimespecs(struct timespec *result, const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
result->tv_sec = a->tv_sec - b->tv_sec;
|
||||
result->tv_nsec = a->tv_nsec - b->tv_nsec;
|
||||
@@ -176,7 +176,7 @@ UTI_DiffTimespecs(struct timespec *result, struct timespec *a, struct timespec *
|
||||
|
||||
/* Calculate result = a - b and return as a double */
|
||||
double
|
||||
UTI_DiffTimespecsToDouble(struct timespec *a, struct timespec *b)
|
||||
UTI_DiffTimespecsToDouble(const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
return ((double)a->tv_sec - (double)b->tv_sec) + 1.0e-9 * (a->tv_nsec - b->tv_nsec);
|
||||
}
|
||||
@@ -184,7 +184,7 @@ UTI_DiffTimespecsToDouble(struct timespec *a, struct timespec *b)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_AddDoubleToTimespec(struct timespec *start, double increment, struct timespec *end)
|
||||
UTI_AddDoubleToTimespec(const struct timespec *start, double increment, struct timespec *end)
|
||||
{
|
||||
time_t int_part;
|
||||
|
||||
@@ -198,7 +198,7 @@ UTI_AddDoubleToTimespec(struct timespec *start, double increment, struct timespe
|
||||
|
||||
/* Calculate the average and difference (as a double) of two timespecs */
|
||||
void
|
||||
UTI_AverageDiffTimespecs(struct timespec *earlier, struct timespec *later,
|
||||
UTI_AverageDiffTimespecs(const struct timespec *earlier, const struct timespec *later,
|
||||
struct timespec *average, double *diff)
|
||||
{
|
||||
*diff = UTI_DiffTimespecsToDouble(later, earlier);
|
||||
@@ -208,8 +208,8 @@ UTI_AverageDiffTimespecs(struct timespec *earlier, struct timespec *later,
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_AddDiffToTimespec(struct timespec *a, struct timespec *b,
|
||||
struct timespec *c, struct timespec *result)
|
||||
UTI_AddDiffToTimespec(const struct timespec *a, const struct timespec *b,
|
||||
const struct timespec *c, struct timespec *result)
|
||||
{
|
||||
double diff;
|
||||
|
||||
@@ -230,7 +230,7 @@ static int pool_ptr = 0;
|
||||
/* Convert a timespec into a temporary string, largely for diagnostic display */
|
||||
|
||||
char *
|
||||
UTI_TimespecToString(struct timespec *ts)
|
||||
UTI_TimespecToString(const struct timespec *ts)
|
||||
{
|
||||
char *result;
|
||||
|
||||
@@ -250,7 +250,7 @@ UTI_TimespecToString(struct timespec *ts)
|
||||
for diagnostic display */
|
||||
|
||||
char *
|
||||
UTI_Ntp64ToString(NTP_int64 *ntp_ts)
|
||||
UTI_Ntp64ToString(const NTP_int64 *ntp_ts)
|
||||
{
|
||||
struct timespec ts;
|
||||
UTI_Ntp64ToTimespec(ntp_ts, &ts);
|
||||
@@ -281,10 +281,10 @@ UTI_RefidToString(uint32_t ref_id)
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
UTI_IPToString(IPAddr *addr)
|
||||
UTI_IPToString(const IPAddr *addr)
|
||||
{
|
||||
unsigned long a, b, c, d, ip;
|
||||
uint8_t *ip6;
|
||||
const uint8_t *ip6;
|
||||
char *result;
|
||||
|
||||
result = NEXT_BUFFER;
|
||||
@@ -375,7 +375,7 @@ UTI_StringToIdIP(const char *addr, IPAddr *ip)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
UTI_IsIPReal(IPAddr *ip)
|
||||
UTI_IsIPReal(const IPAddr *ip)
|
||||
{
|
||||
switch (ip->family) {
|
||||
case IPADDR_INET4:
|
||||
@@ -389,7 +389,7 @@ UTI_IsIPReal(IPAddr *ip)
|
||||
/* ================================================== */
|
||||
|
||||
uint32_t
|
||||
UTI_IPToRefid(IPAddr *ip)
|
||||
UTI_IPToRefid(const IPAddr *ip)
|
||||
{
|
||||
static int MD5_hash = -1;
|
||||
unsigned char buf[16];
|
||||
@@ -414,10 +414,10 @@ UTI_IPToRefid(IPAddr *ip)
|
||||
/* ================================================== */
|
||||
|
||||
uint32_t
|
||||
UTI_IPToHash(IPAddr *ip)
|
||||
UTI_IPToHash(const IPAddr *ip)
|
||||
{
|
||||
static uint32_t seed = 0;
|
||||
unsigned char *addr;
|
||||
const unsigned char *addr;
|
||||
unsigned int i, len;
|
||||
uint32_t hash;
|
||||
|
||||
@@ -452,7 +452,7 @@ UTI_IPToHash(IPAddr *ip)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_IPHostToNetwork(IPAddr *src, IPAddr *dest)
|
||||
UTI_IPHostToNetwork(const IPAddr *src, IPAddr *dest)
|
||||
{
|
||||
/* Don't send uninitialized bytes over network */
|
||||
memset(dest, 0, sizeof (IPAddr));
|
||||
@@ -477,7 +477,7 @@ UTI_IPHostToNetwork(IPAddr *src, IPAddr *dest)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest)
|
||||
UTI_IPNetworkToHost(const IPAddr *src, IPAddr *dest)
|
||||
{
|
||||
dest->family = ntohs(src->family);
|
||||
dest->_pad = 0;
|
||||
@@ -500,7 +500,7 @@ UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask)
|
||||
UTI_CompareIPs(const IPAddr *a, const IPAddr *b, const IPAddr *mask)
|
||||
{
|
||||
int i, d;
|
||||
|
||||
@@ -536,7 +536,7 @@ UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask)
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
UTI_IPSockAddrToString(IPSockAddr *sa)
|
||||
UTI_IPSockAddrToString(const IPSockAddr *sa)
|
||||
{
|
||||
char *result;
|
||||
|
||||
@@ -571,7 +571,8 @@ UTI_TimeToLogForm(time_t t)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_AdjustTimespec(struct timespec *old_ts, struct timespec *when, struct timespec *new_ts, double *delta_time, double dfreq, double doffset)
|
||||
UTI_AdjustTimespec(const struct timespec *old_ts, const struct timespec *when,
|
||||
struct timespec *new_ts, double *delta_time, double dfreq, double doffset)
|
||||
{
|
||||
double elapsed;
|
||||
|
||||
@@ -644,7 +645,7 @@ UTI_ZeroNtp64(NTP_int64 *ts)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
UTI_IsZeroNtp64(NTP_int64 *ts)
|
||||
UTI_IsZeroNtp64(const NTP_int64 *ts)
|
||||
{
|
||||
return !ts->hi && !ts->lo;
|
||||
}
|
||||
@@ -652,7 +653,7 @@ UTI_IsZeroNtp64(NTP_int64 *ts)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
UTI_CompareNtp64(NTP_int64 *a, NTP_int64 *b)
|
||||
UTI_CompareNtp64(const NTP_int64 *a, const NTP_int64 *b)
|
||||
{
|
||||
int32_t diff;
|
||||
|
||||
@@ -672,7 +673,8 @@ UTI_CompareNtp64(NTP_int64 *a, NTP_int64 *b)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
UTI_IsEqualAnyNtp64(NTP_int64 *a, NTP_int64 *b1, NTP_int64 *b2, NTP_int64 *b3)
|
||||
UTI_IsEqualAnyNtp64(const NTP_int64 *a, const NTP_int64 *b1, const NTP_int64 *b2,
|
||||
const NTP_int64 *b3)
|
||||
{
|
||||
if (b1 && a->lo == b1->lo && a->hi == b1->hi)
|
||||
return 1;
|
||||
@@ -694,7 +696,7 @@ UTI_IsEqualAnyNtp64(NTP_int64 *a, NTP_int64 *b1, NTP_int64 *b2, NTP_int64 *b3)
|
||||
#define NSEC_PER_NTP64 4.294967296
|
||||
|
||||
void
|
||||
UTI_TimespecToNtp64(struct timespec *src, NTP_int64 *dest, NTP_int64 *fuzz)
|
||||
UTI_TimespecToNtp64(const struct timespec *src, NTP_int64 *dest, const NTP_int64 *fuzz)
|
||||
{
|
||||
uint32_t hi, lo, sec, nsec;
|
||||
|
||||
@@ -723,7 +725,7 @@ UTI_TimespecToNtp64(struct timespec *src, NTP_int64 *dest, NTP_int64 *fuzz)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_Ntp64ToTimespec(NTP_int64 *src, struct timespec *dest)
|
||||
UTI_Ntp64ToTimespec(const NTP_int64 *src, struct timespec *dest)
|
||||
{
|
||||
uint32_t ntp_sec, ntp_frac;
|
||||
|
||||
@@ -755,7 +757,7 @@ UTI_Ntp64ToTimespec(NTP_int64 *src, struct timespec *dest)
|
||||
#define MIN_ENDOFTIME_DISTANCE (365 * 24 * 3600)
|
||||
|
||||
int
|
||||
UTI_IsTimeOffsetSane(struct timespec *ts, double offset)
|
||||
UTI_IsTimeOffsetSane(const struct timespec *ts, double offset)
|
||||
{
|
||||
double t;
|
||||
|
||||
@@ -801,7 +803,7 @@ UTI_Log2ToDouble(int l)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_TimespecNetworkToHost(Timespec *src, struct timespec *dest)
|
||||
UTI_TimespecNetworkToHost(const Timespec *src, struct timespec *dest)
|
||||
{
|
||||
uint32_t sec_low, nsec;
|
||||
#ifdef HAVE_LONG_TIME_T
|
||||
@@ -826,7 +828,7 @@ UTI_TimespecNetworkToHost(Timespec *src, struct timespec *dest)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_TimespecHostToNetwork(struct timespec *src, Timespec *dest)
|
||||
UTI_TimespecHostToNetwork(const struct timespec *src, Timespec *dest)
|
||||
{
|
||||
dest->tv_nsec = htonl(src->tv_nsec);
|
||||
#ifdef HAVE_LONG_TIME_T
|
||||
@@ -1400,3 +1402,33 @@ UTI_HexToBytes(const char *hex, void *buf, unsigned int len)
|
||||
|
||||
return *hex == '\0' ? i : 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
UTI_SplitString(char *string, char **words, int max_saved_words)
|
||||
{
|
||||
char *s = string;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < max_saved_words; i++)
|
||||
words[i] = NULL;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
/* Zero white-space characters before the word */
|
||||
while (*s != '\0' && isspace((unsigned char)*s))
|
||||
*s++ = '\0';
|
||||
|
||||
if (*s == '\0')
|
||||
break;
|
||||
|
||||
if (i < max_saved_words)
|
||||
words[i] = s;
|
||||
|
||||
/* Find the next word */
|
||||
while (*s != '\0' && !isspace((unsigned char)*s))
|
||||
s++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
71
util.h
71
util.h
@@ -41,13 +41,13 @@ extern void UTI_ZeroTimespec(struct timespec *ts);
|
||||
extern int UTI_IsZeroTimespec(struct timespec *ts);
|
||||
|
||||
/* Convert a timeval into a timespec */
|
||||
extern void UTI_TimevalToTimespec(struct timeval *tv, struct timespec *ts);
|
||||
extern void UTI_TimevalToTimespec(const struct timeval *tv, struct timespec *ts);
|
||||
|
||||
/* Convert a timespec into a timeval */
|
||||
extern void UTI_TimespecToTimeval(struct timespec *ts, struct timeval *tv);
|
||||
extern void UTI_TimespecToTimeval(const struct timespec *ts, struct timeval *tv);
|
||||
|
||||
/* Convert a timespec into a floating point number of seconds */
|
||||
extern double UTI_TimespecToDouble(struct timespec *ts);
|
||||
extern double UTI_TimespecToDouble(const struct timespec *ts);
|
||||
|
||||
/* Convert a number of seconds expressed in floating point into a
|
||||
timespec */
|
||||
@@ -58,7 +58,7 @@ extern void UTI_DoubleToTimespec(double d, struct timespec *ts);
|
||||
extern void UTI_NormaliseTimespec(struct timespec *ts);
|
||||
|
||||
/* Convert a timeval into a floating point number of seconds */
|
||||
extern double UTI_TimevalToDouble(struct timeval *tv);
|
||||
extern double UTI_TimevalToDouble(const struct timeval *tv);
|
||||
|
||||
/* Convert a number of seconds expressed in floating point into a
|
||||
timeval */
|
||||
@@ -70,54 +70,60 @@ extern void UTI_NormaliseTimeval(struct timeval *x);
|
||||
|
||||
/* Returns -1 if a comes earlier than b, 0 if a is the same time as b,
|
||||
and +1 if a comes after b */
|
||||
extern int UTI_CompareTimespecs(struct timespec *a, struct timespec *b);
|
||||
extern int UTI_CompareTimespecs(const struct timespec *a, const struct timespec *b);
|
||||
|
||||
/* Calculate result = a - b */
|
||||
extern void UTI_DiffTimespecs(struct timespec *result, struct timespec *a, struct timespec *b);
|
||||
extern void UTI_DiffTimespecs(struct timespec *result,
|
||||
const struct timespec *a, const struct timespec *b);
|
||||
|
||||
/* Calculate result = a - b and return as a double */
|
||||
extern double UTI_DiffTimespecsToDouble(struct timespec *a, struct timespec *b);
|
||||
extern double UTI_DiffTimespecsToDouble(const struct timespec *a, const struct timespec *b);
|
||||
|
||||
/* Add a double increment to a timespec to get a new one. 'start' is
|
||||
the starting time, 'end' is the result that we return. This is
|
||||
safe to use if start and end are the same */
|
||||
extern void UTI_AddDoubleToTimespec(struct timespec *start, double increment, struct timespec *end);
|
||||
extern void UTI_AddDoubleToTimespec(const struct timespec *start, double increment,
|
||||
struct timespec *end);
|
||||
|
||||
/* Calculate the average and difference (as a double) of two timespecs */
|
||||
extern void UTI_AverageDiffTimespecs(struct timespec *earlier, struct timespec *later, struct timespec *average, double *diff);
|
||||
extern void UTI_AverageDiffTimespecs(const struct timespec *earlier, const struct timespec *later,
|
||||
struct timespec *average, double *diff);
|
||||
|
||||
/* Calculate result = a - b + c */
|
||||
extern void UTI_AddDiffToTimespec(struct timespec *a, struct timespec *b, struct timespec *c, struct timespec *result);
|
||||
extern void UTI_AddDiffToTimespec(const struct timespec *a, const struct timespec *b,
|
||||
const struct timespec *c, struct timespec *result);
|
||||
|
||||
/* Convert a timespec into a temporary string, largely for diagnostic
|
||||
display */
|
||||
extern char *UTI_TimespecToString(struct timespec *ts);
|
||||
extern char *UTI_TimespecToString(const struct timespec *ts);
|
||||
|
||||
/* Convert an NTP timestamp into a temporary string, largely for
|
||||
diagnostic display */
|
||||
extern char *UTI_Ntp64ToString(NTP_int64 *ts);
|
||||
extern char *UTI_Ntp64ToString(const NTP_int64 *ts);
|
||||
|
||||
/* Convert ref_id into a temporary string, for diagnostics */
|
||||
extern char *UTI_RefidToString(uint32_t ref_id);
|
||||
|
||||
/* Convert an IP address to string, for diagnostics */
|
||||
extern char *UTI_IPToString(IPAddr *ip);
|
||||
extern char *UTI_IPToString(const IPAddr *ip);
|
||||
|
||||
extern int UTI_StringToIP(const char *addr, IPAddr *ip);
|
||||
extern int UTI_StringToIdIP(const char *addr, IPAddr *ip);
|
||||
extern int UTI_IsIPReal(IPAddr *ip);
|
||||
extern uint32_t UTI_IPToRefid(IPAddr *ip);
|
||||
extern uint32_t UTI_IPToHash(IPAddr *ip);
|
||||
extern void UTI_IPHostToNetwork(IPAddr *src, IPAddr *dest);
|
||||
extern void UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest);
|
||||
extern int UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask);
|
||||
extern int UTI_IsIPReal(const IPAddr *ip);
|
||||
extern uint32_t UTI_IPToRefid(const IPAddr *ip);
|
||||
extern uint32_t UTI_IPToHash(const IPAddr *ip);
|
||||
extern void UTI_IPHostToNetwork(const IPAddr *src, IPAddr *dest);
|
||||
extern void UTI_IPNetworkToHost(const IPAddr *src, IPAddr *dest);
|
||||
extern int UTI_CompareIPs(const IPAddr *a, const IPAddr *b, const IPAddr *mask);
|
||||
|
||||
extern char *UTI_IPSockAddrToString(IPSockAddr *sa);
|
||||
extern char *UTI_IPSockAddrToString(const IPSockAddr *sa);
|
||||
|
||||
extern char *UTI_TimeToLogForm(time_t t);
|
||||
|
||||
/* Adjust time following a frequency/offset change */
|
||||
extern void UTI_AdjustTimespec(struct timespec *old_ts, struct timespec *when, struct timespec *new_ts, double *delta_time, double dfreq, double doffset);
|
||||
extern void UTI_AdjustTimespec(const struct timespec *old_ts, const struct timespec *when,
|
||||
struct timespec *new_ts, double *delta_time,
|
||||
double dfreq, double doffset);
|
||||
|
||||
/* Get zero NTP timestamp with random bits below precision */
|
||||
extern void UTI_GetNtp64Fuzz(NTP_int64 *ts, int precision);
|
||||
@@ -129,30 +135,32 @@ extern NTP_int32 UTI_DoubleToNtp32(double x);
|
||||
extern void UTI_ZeroNtp64(NTP_int64 *ts);
|
||||
|
||||
/* Check if an NTP timestamp is zero */
|
||||
extern int UTI_IsZeroNtp64(NTP_int64 *ts);
|
||||
extern int UTI_IsZeroNtp64(const NTP_int64 *ts);
|
||||
|
||||
/* Compare two NTP timestamps. Returns -1 if a is before b, 0 if a is equal to
|
||||
b, and 1 if a is after b. */
|
||||
extern int UTI_CompareNtp64(NTP_int64 *a, NTP_int64 *b);
|
||||
extern int UTI_CompareNtp64(const NTP_int64 *a, const NTP_int64 *b);
|
||||
|
||||
/* Compare an NTP timestamp with up to three other timestamps. Returns 0
|
||||
if a is not equal to any of b1, b2, and b3, 1 otherwise. */
|
||||
extern int UTI_IsEqualAnyNtp64(NTP_int64 *a, NTP_int64 *b1, NTP_int64 *b2, NTP_int64 *b3);
|
||||
extern int UTI_IsEqualAnyNtp64(const NTP_int64 *a, const NTP_int64 *b1,
|
||||
const NTP_int64 *b2, const NTP_int64 *b3);
|
||||
|
||||
/* Convert a timespec into an NTP timestamp */
|
||||
extern void UTI_TimespecToNtp64(struct timespec *src, NTP_int64 *dest, NTP_int64 *fuzz);
|
||||
extern void UTI_TimespecToNtp64(const struct timespec *src, NTP_int64 *dest,
|
||||
const NTP_int64 *fuzz);
|
||||
|
||||
/* Convert an NTP timestamp into a timespec */
|
||||
extern void UTI_Ntp64ToTimespec(NTP_int64 *src, struct timespec *dest);
|
||||
extern void UTI_Ntp64ToTimespec(const NTP_int64 *src, struct timespec *dest);
|
||||
|
||||
/* Check if time + offset is sane */
|
||||
extern int UTI_IsTimeOffsetSane(struct timespec *ts, double offset);
|
||||
extern int UTI_IsTimeOffsetSane(const struct timespec *ts, double offset);
|
||||
|
||||
/* Get 2 raised to power of a signed integer */
|
||||
extern double UTI_Log2ToDouble(int l);
|
||||
|
||||
extern void UTI_TimespecNetworkToHost(Timespec *src, struct timespec *dest);
|
||||
extern void UTI_TimespecHostToNetwork(struct timespec *src, Timespec *dest);
|
||||
extern void UTI_TimespecNetworkToHost(const Timespec *src, struct timespec *dest);
|
||||
extern void UTI_TimespecHostToNetwork(const struct timespec *src, Timespec *dest);
|
||||
|
||||
extern double UTI_FloatNetworkToHost(Float x);
|
||||
extern Float UTI_FloatHostToNetwork(double x);
|
||||
@@ -212,6 +220,11 @@ extern int UTI_BytesToHex(const void *buf, unsigned int buf_len, char *hex, unsi
|
||||
is supported. */
|
||||
extern unsigned int UTI_HexToBytes(const char *hex, void *buf, unsigned int len);
|
||||
|
||||
/* Split a string into words separated by whitespace characters. It returns
|
||||
the number of words found in the string, but saves only up to the specified
|
||||
number of pointers to the words. */
|
||||
extern int UTI_SplitString(char *string, char **words, int max_saved_words);
|
||||
|
||||
/* Macros to get maximum and minimum of two values */
|
||||
#ifdef MAX
|
||||
#undef MAX
|
||||
|
||||
Reference in New Issue
Block a user