Compare commits

...

21 Commits

Author SHA1 Message Date
Miroslav Lichvar
fe2dbfb6cb Update NEWS 2010-02-04 13:07:19 +01:00
Miroslav Lichvar
032ac800aa Limit rate of syslog messages
Error messages caused by incoming packets need to be rate limited
to avoid filling up disk space.
2010-02-04 13:07:19 +01:00
Miroslav Lichvar
5e86eeacfb Don't reply to invalid chronyc packets 2010-02-04 13:07:19 +01:00
Miroslav Lichvar
75b7d33fb7 Update list of commands not using authentication in documentation 2010-02-04 13:07:19 +01:00
Miroslav Lichvar
a6e532442b Initialize local_ntp_tx in ntp_core
This fixes another valgrind error.
2010-02-04 12:42:48 +01:00
Miroslav Lichvar
a123a12f59 Allow to set only permission bits with perm option 2010-01-29 09:50:51 +01:00
Miroslav Lichvar
f261251a9b Add perm option to SHM driver 2010-01-28 10:10:16 +01:00
Miroslav Lichvar
a0e1154bfb Add common refclock driver option parsing 2010-01-28 10:10:16 +01:00
Miroslav Lichvar
e261278a5c Add lock option for PPS refclocks 2010-01-28 10:10:13 +01:00
Miroslav Lichvar
dbb550e6db Don't start chronyd with unrecognized command line options 2010-01-27 13:53:49 +01:00
Hattink, Tjalling (FINT)
27a9b0e7b1 Fix scheduler to allow stepping clock from timeout handler 2010-01-26 17:20:08 +01:00
Miroslav Lichvar
8a00758cf5 Add makestep directive 2010-01-25 15:51:15 +01:00
Miroslav Lichvar
15e154c09d Handle immediate step in local module instead of system driver
This fixes the problem where scheduler wasn't notified about performed
steps and it also makes the command available on all supported systems.
2010-01-25 15:51:15 +01:00
Miroslav Lichvar
52d0c9a057 Limit timeout for end of slew to avoid overflow 2010-01-25 15:50:45 +01:00
Miroslav Lichvar
4593471ad5 Don't require _bigadj kernel symbol in NetBSD driver 2010-01-13 14:40:13 +01:00
Miroslav Lichvar
a3288d4284 Print only printable characters from refid 2010-01-13 14:00:12 +01:00
Miroslav Lichvar
22f0da4da6 Fix name resolving on NetBSD 2010-01-12 18:28:04 +01:00
Miroslav Lichvar
baa977a3ed Increase buffers used to print IPv6 addresses 2010-01-12 18:05:41 +01:00
Miroslav Lichvar
b4b2491015 Return 0 from DNS_IPAddress2Name when name was truncated 2010-01-12 17:58:03 +01:00
Miroslav Lichvar
902ed3c694 Write banner to tracking log when not synchronized 2010-01-12 16:59:11 +01:00
Bill Unruh
4a9205b341 Log warning when changing file ownership fails 2009-12-20 12:29:24 +01:00
28 changed files with 396 additions and 198 deletions

12
NEWS
View File

@@ -1,6 +1,14 @@
New in version 1.24 New in version 1.24
=================== ===================
Security fixes
--------------
* Don't reply to invalid cmdmon packets (CVE-2010-0292)
* Limit client log memory size (CVE-2010-0293)
* Limit rate of syslog messages (CVE-2010-0294)
Bug fixes/Enhancements
----------------------
* Support for reference clocks (SHM, SOCK, PPS drivers) * Support for reference clocks (SHM, SOCK, PPS drivers)
* IPv6 support * IPv6 support
* Linux capabilities support (to drop root privileges) * Linux capabilities support (to drop root privileges)
@@ -12,8 +20,10 @@ New in version 1.24
* NTP client support for KoD RATE * NTP client support for KoD RATE
* Read kernel timestamps for received NTP packets * Read kernel timestamps for received NTP packets
* Reply to NTP requests with correct address on multihomed hosts * Reply to NTP requests with correct address on multihomed hosts
* Add option to limit client log memory size
* Retry name resolving after temporary failure * Retry name resolving after temporary failure
* Fix makestep command, make it available on all systems
* Add makestep directive for automatic clock stepping
* Don't require _bigadj kernel symbol on NetBSD
* Avoid blocking read in Linux RTC driver * Avoid blocking read in Linux RTC driver
* Support for Linux on S/390 and PowerPC * Support for Linux on S/390 and PowerPC
* Fix various bugs on 64-bit systems * Fix various bugs on 64-bit systems

View File

@@ -1184,6 +1184,7 @@ directives can occur in any order in the file.
* logchange directive:: Generate syslog messages if large offsets occur * logchange directive:: Generate syslog messages if large offsets occur
* logdir directive:: Specify directory for logging * logdir directive:: Specify directory for logging
* mailonchange directive:: Send email if a clock correction above a threshold occurs * mailonchange directive:: Send email if a clock correction above a threshold occurs
* makestep directive:: Step system clock if large correction is needed
* manual directive:: Allow manual entry using chronyc's settime cmd. * manual directive:: Allow manual entry using chronyc's settime cmd.
* maxupdateskew directive:: Stop bad estimates upsetting machine clock * maxupdateskew directive:: Stop bad estimates upsetting machine clock
* noclientlog directive:: Prevent chronyd from gathering data about clients * noclientlog directive:: Prevent chronyd from gathering data about clients
@@ -2085,6 +2086,32 @@ mailonchange root@@localhost 0.5
This would send a mail message to root if a change of more than 0.5 This would send a mail message to root if a change of more than 0.5
seconds were applied to the system clock. seconds were applied to the system clock.
@c }}} @c }}}
@c {{{ makestep
@node makestep directive
@subsection makestep
Normally chronyd will cause the system to gradually correct any time
offset, by slowing down or speeding up the clock as required. In
certain situations, the system clock may be so far adrift that this
slewing process would take a very long time to correct the system clock.
This directive forces @code{chronyd} to step system clock if the
adjustment is larger than a threshold value, but only if there were no
more clock updates since @code{chronyd} was started than a specified
limit (a negative value can be used to disable the limit).
This is particularly useful when using reference clocks, because the
@code{initstepslew} directive (@pxref{initstepslew directive}) works
only with NTP sources.
An example of the use of this directive is
@example
makestep 1000 10
@end example
This would step system clock if the adjustment is larger than 1000
seconds, but only in the first ten clock updates.
@c }}}
@c {{{ manual @c {{{ manual
@node manual directive @node manual directive
@subsection manual @subsection manual
@@ -2202,8 +2229,8 @@ There are currently three drivers implemented:
@table @code @table @code
@item PPS @item PPS
Pulse per second (PPS) API driver. The parameter is a path to the PPS Pulse per second (PPS) API driver. The parameter is a path to the PPS
device. Assert events are used by default. The path can have device. Assert events are used by default. Driver option
:1 appended to use clear events instead. @code{:clear} can be appended to the path to use clear events instead.
PPS refclock needs another source (NTP or non-PPS refclock) or local PPS refclock needs another source (NTP or non-PPS refclock) or local
directive (@pxref{local directive}) enabled to function. For example: directive (@pxref{local directive}) enabled to function. For example:
@@ -2215,14 +2242,18 @@ refclock PPS /dev/pps0
@item SHM @item SHM
NTP shared memory driver. The parameter is the number of the NTP shared memory driver. The parameter is the number of the
shared memory segment that should be used to read timestamps, usually shared memory segment that should be used for receiving timestamps, usually
0, 1, 2 or 3. For example: 0, 1, 2 or 3. For example:
@example @example
refclock SHM 1 poll 3 refid GPS1 refclock SHM 1 poll 3 refid GPS1
@end example @end example
Software that can be used as a source of timestamps includes A driver option in form @code{:perm=NNN} can be appended to the
segment number to create the segment with permissions other than the
default @code{0600}.
Software that can be used as a source of reference time includes
@code{gpsd} and @code{shmpps}. @code{gpsd} and @code{shmpps}.
@item SOCK @item SOCK
Unix domain socket driver. The parameter is a path to the socket Unix domain socket driver. The parameter is a path to the socket
@@ -2262,6 +2293,12 @@ PPS signal frequency (in Hz). This option only controls how the
received pulses are aligned. To actually receive more than one received pulses are aligned. To actually receive more than one
pulse per second, a negative @code{dpoll} has to be specified (-3 for pulse per second, a negative @code{dpoll} has to be specified (-3 for
5Hz signal). The default is 1. 5Hz signal). The default is 1.
@item lock
This option can be used to lock a PPS refclock to another refclock
whose reference id is specified by this option. In this mode received
pulses are aligned directly to unfiltered samples from the refclock.
By default, pulses are aligned to local clock, but only when it is
well synchronised.
@item offset @item offset
This option can be used to compensate a constant error. The specified This option can be used to compensate a constant error. The specified
offset (in seconds) is applied to all samples produced by the offset (in seconds) is applied to all samples produced by the
@@ -2586,6 +2623,8 @@ Only the following commands can be used @emph{without} providing a
password: password:
@itemize @bullet @itemize @bullet
@item @code{activity}
@item @code{clients}
@item @code{dns} @item @code{dns}
@item @code{exit} @item @code{exit}
@item @code{help} @item @code{help}
@@ -3076,8 +3115,9 @@ BE WARNED - certain software will be seriously affected by such jumps to
the system time. (That is the reason why chronyd uses slewing the system time. (That is the reason why chronyd uses slewing
normally.) normally.)
The @code{makestep} command is currently only available on the Linux The @code{makestep} directive in the configuration file can be used
version of chrony. to step the clock automatically when the adjustment is larger than a
specified threshold, see @ref{makestep directive}.
@c }}} @c }}}
@c {{{ manual @c {{{ manual
@node manual command @node manual command

View File

@@ -1558,7 +1558,7 @@ process_cmd_sources(char *line)
uint32_t latest_meas_ago; uint32_t latest_meas_ago;
uint16_t poll, stratum; uint16_t poll, stratum;
uint16_t state, mode; uint16_t state, mode;
char hostname_buf[32]; char hostname_buf[50];
/* Check whether to output verbose headers */ /* Check whether to output verbose headers */
verbose = check_for_verbose_flag(line); verbose = check_for_verbose_flag(line);
@@ -1658,7 +1658,7 @@ process_cmd_sourcestats(char *line)
int n_sources, i; int n_sources, i;
int verbose = 0; int verbose = 0;
char hostname_buf[32]; char hostname_buf[50];
unsigned long n_samples, n_runs, span_seconds; unsigned long n_samples, n_runs, span_seconds;
double resid_freq_ppm, skew_ppm, sd, est_offset, est_offset_err; double resid_freq_ppm, skew_ppm, sd, est_offset, est_offset_err;
unsigned long ref_id; unsigned long ref_id;
@@ -1859,7 +1859,7 @@ process_cmd_clients(char *line)
unsigned long cmd_hits_bad; unsigned long cmd_hits_bad;
unsigned long last_ntp_hit_ago; unsigned long last_ntp_hit_ago;
unsigned long last_cmd_hit_ago; unsigned long last_cmd_hit_ago;
char hostname_buf[32]; char hostname_buf[50];
int n_replies; int n_replies;
@@ -2044,7 +2044,7 @@ process_cmd_clients(char *line)
unsigned long cmd_hits_bad; unsigned long cmd_hits_bad;
unsigned long last_ntp_hit_ago; unsigned long last_ntp_hit_ago;
unsigned long last_cmd_hit_ago; unsigned long last_cmd_hit_ago;
char hostname_buf[32]; char hostname_buf[50];
int n_replies; int n_replies;
int n_indices_in_table; int n_indices_in_table;

View File

@@ -746,7 +746,7 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to)
status = sendto(sock_fd, (void *) msg, tx_message_length, 0, status = sendto(sock_fd, (void *) msg, tx_message_length, 0,
&where_to->u, addrlen); &where_to->u, addrlen);
if (status < 0) { if (status < 0 && !LOG_RateLimited()) {
unsigned short port; unsigned short port;
IPAddr ip; IPAddr ip;
@@ -1676,13 +1676,8 @@ handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
static void static void
handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message) handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message)
{ {
int status; LCL_MakeStep(0.0);
status = LCL_MakeStep();
if (status) {
tx_message->status = htons(STT_SUCCESS); tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_NOTENABLED);
}
return; return;
} }
@@ -1739,6 +1734,7 @@ read_from_cmd_socket(void *anything)
int valid_ts; int valid_ts;
int authenticated; int authenticated;
int localhost; int localhost;
int allowed;
unsigned short rx_command; unsigned short rx_command;
unsigned long rx_message_token; unsigned long rx_message_token;
unsigned long tx_message_token; unsigned long tx_message_token;
@@ -1809,26 +1805,7 @@ read_from_cmd_socket(void *anything)
assert(0); assert(0);
} }
if ((!ADF_IsAllowed(access_auth_table, &remote_ip)) && allowed = ADF_IsAllowed(access_auth_table, &remote_ip) || localhost;
(!localhost)) {
/* The client is not allowed access, so don't waste any more time
on him. Note that localhost is always allowed access
regardless of the defined access rules - otherwise, we could
shut ourselves out completely! */
/* We ought to find another way to log this, there is an attack
here against the host because an adversary can just keep
hitting us with bad packets until our log file(s) fill up. */
LOG(LOGS_WARN, LOGF_CmdMon, "Command packet received from unauthorised host %s port %d",
UTI_IPToString(&remote_ip),
remote_port);
tx_message.status = htons(STT_NOHOSTACCESS);
transmit_reply(&tx_message, &where_from);
return;
}
if (read_length < offsetof(CMD_Request, data) || if (read_length < offsetof(CMD_Request, data) ||
rx_message.pkt_type != PKT_TYPE_CMD_REQUEST || rx_message.pkt_type != PKT_TYPE_CMD_REQUEST ||
@@ -1836,6 +1813,7 @@ read_from_cmd_socket(void *anything)
rx_message.res2 != 0) { rx_message.res2 != 0) {
/* We don't know how to process anything like this */ /* We don't know how to process anything like this */
if (allowed)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec); CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
return; return;
@@ -1843,7 +1821,10 @@ read_from_cmd_socket(void *anything)
if (rx_message.version != PROTO_VERSION_NUMBER) { if (rx_message.version != PROTO_VERSION_NUMBER) {
tx_message.status = htons(STT_NOHOSTACCESS); tx_message.status = htons(STT_NOHOSTACCESS);
if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Read packet with protocol version %d (expected %d) from %s:%hu", rx_message.version, PROTO_VERSION_NUMBER, UTI_IPToString(&remote_ip), remote_port); LOG(LOGS_WARN, LOGF_CmdMon, "Read packet with protocol version %d (expected %d) from %s:%hu", rx_message.version, PROTO_VERSION_NUMBER, UTI_IPToString(&remote_ip), remote_port);
}
if (allowed)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec); CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT) { if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT) {
@@ -1854,7 +1835,10 @@ read_from_cmd_socket(void *anything)
} }
if (read_length != expected_length) { if (read_length != expected_length) {
if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Read incorrectly sized packet from %s:%hu", UTI_IPToString(&remote_ip), remote_port); LOG(LOGS_WARN, LOGF_CmdMon, "Read incorrectly sized packet from %s:%hu", UTI_IPToString(&remote_ip), remote_port);
}
if (allowed)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec); CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
tx_message.status = htons(STT_BADPKTLENGTH); tx_message.status = htons(STT_BADPKTLENGTH);
@@ -1862,6 +1846,24 @@ read_from_cmd_socket(void *anything)
return; return;
} }
if (!allowed) {
/* The client is not allowed access, so don't waste any more time
on him. Note that localhost is always allowed access
regardless of the defined access rules - otherwise, we could
shut ourselves out completely! */
if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Command packet received from unauthorised host %s port %d",
UTI_IPToString(&remote_ip),
remote_port);
}
tx_message.status = htons(STT_NOHOSTACCESS);
transmit_reply(&tx_message, &where_from);
return;
}
rx_command = ntohs(rx_message.command); rx_command = ntohs(rx_message.command);
/* OK, we have a valid message. Now dispatch on message type and process it. */ /* OK, we have a valid message. Now dispatch on message type and process it. */
@@ -1938,7 +1940,7 @@ read_from_cmd_socket(void *anything)
tx_message_length = PKL_ReplyLength(prev_tx_message); tx_message_length = PKL_ReplyLength(prev_tx_message);
status = sendto(sock_fd, (void *) prev_tx_message, tx_message_length, 0, status = sendto(sock_fd, (void *) prev_tx_message, tx_message_length, 0,
&where_from.u, from_length); &where_from.u, from_length);
if (status < 0) { if (status < 0 && !LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&remote_ip), remote_port); LOG(LOGS_WARN, LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&remote_ip), remote_port);
} }
return; return;
@@ -1994,7 +1996,7 @@ read_from_cmd_socket(void *anything)
tx_message.status = htons(STT_INVALID); tx_message.status = htons(STT_INVALID);
tx_message.reply = htons(RPY_NULL); tx_message.reply = htons(RPY_NULL);
} else { } else {
int allowed = 0; allowed = 0;
/* Check level of authority required to issue the command */ /* Check level of authority required to issue the command */
switch(permissions[rx_command]) { switch(permissions[rx_command]) {
@@ -2064,7 +2066,7 @@ read_from_cmd_socket(void *anything)
case REQ_LOGON: case REQ_LOGON:
/* If the log-on fails, record the reason why */ /* If the log-on fails, record the reason why */
if (!issue_token) { if (!issue_token && !LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, LOG(LOGS_WARN, LOGF_CmdMon,
"Bad command logon from %s port %d (md5_ok=%d valid_ts=%d)\n", "Bad command logon from %s port %d (md5_ok=%d valid_ts=%d)\n",
UTI_IPToString(&remote_ip), UTI_IPToString(&remote_ip),

36
conf.c
View File

@@ -92,6 +92,7 @@ static void parse_cmdport(const char *);
static void parse_rtconutc(const char *); static void parse_rtconutc(const char *);
static void parse_noclientlog(const char *); static void parse_noclientlog(const char *);
static void parse_clientloglimit(const char *); static void parse_clientloglimit(const char *);
static void parse_makestep(const char *);
static void parse_logchange(const char *); static void parse_logchange(const char *);
static void parse_mailonchange(const char *); static void parse_mailonchange(const char *);
static void parse_bindaddress(const char *); static void parse_bindaddress(const char *);
@@ -146,6 +147,10 @@ static int enable_manual=0;
incl. daylight saving). */ incl. daylight saving). */
static int rtc_on_utc = 0; static int rtc_on_utc = 0;
/* Limit and threshold for clock stepping */
static int make_step_limit = 0;
static double make_step_threshold = 0.0;
/* Flag set if we should log to syslog when a time adjustment /* Flag set if we should log to syslog when a time adjustment
exceeding the threshold is initiated */ exceeding the threshold is initiated */
static int do_log_change = 0; static int do_log_change = 0;
@@ -220,6 +225,7 @@ static const Command commands[] = {
{"rtconutc", 8, parse_rtconutc}, {"rtconutc", 8, parse_rtconutc},
{"noclientlog", 11, parse_noclientlog}, {"noclientlog", 11, parse_noclientlog},
{"clientloglimit", 14, parse_clientloglimit}, {"clientloglimit", 14, parse_clientloglimit},
{"makestep", 8, parse_makestep},
{"logchange", 9, parse_logchange}, {"logchange", 9, parse_logchange},
{"mailonchange", 12, parse_mailonchange}, {"mailonchange", 12, parse_mailonchange},
{"bindaddress", 11, parse_bindaddress}, {"bindaddress", 11, parse_bindaddress},
@@ -430,7 +436,7 @@ static void
parse_refclock(const char *line) parse_refclock(const char *line)
{ {
int i, n, poll, dpoll, filter_length, pps_rate; int i, n, poll, dpoll, filter_length, pps_rate;
unsigned long ref_id; unsigned long ref_id, lock_ref_id;
double offset, delay; double offset, delay;
const char *tmp; const char *tmp;
char name[5], cmd[10 + 1], *param; char name[5], cmd[10 + 1], *param;
@@ -447,6 +453,7 @@ parse_refclock(const char *line)
offset = 0.0; offset = 0.0;
delay = 1e-9; delay = 1e-9;
ref_id = 0; ref_id = 0;
lock_ref_id = 0;
if (sscanf(line, "%4s%n", name, &n) != 1) { if (sscanf(line, "%4s%n", name, &n) != 1) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read refclock driver name at line %d", line_number); LOG(LOGS_WARN, LOGF_Configure, "Could not read refclock driver name at line %d", line_number);
@@ -475,6 +482,10 @@ parse_refclock(const char *line)
if (sscanf(line, "%4s%n", (char *)ref, &n) != 1) if (sscanf(line, "%4s%n", (char *)ref, &n) != 1)
break; break;
ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3]; ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
} else if (!strncasecmp(cmd, "lock", 4)) {
if (sscanf(line, "%4s%n", (char *)ref, &n) != 1)
break;
lock_ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
} else if (!strncasecmp(cmd, "poll", 4)) { } else if (!strncasecmp(cmd, "poll", 4)) {
if (sscanf(line, "%d%n", &poll, &n) != 1) { if (sscanf(line, "%d%n", &poll, &n) != 1) {
break; break;
@@ -512,6 +523,7 @@ parse_refclock(const char *line)
refclock_sources[i].offset = offset; refclock_sources[i].offset = offset;
refclock_sources[i].delay = delay; refclock_sources[i].delay = delay;
refclock_sources[i].ref_id = ref_id; refclock_sources[i].ref_id = ref_id;
refclock_sources[i].lock_ref_id = lock_ref_id;
n_refclock_sources++; n_refclock_sources++;
} }
@@ -788,6 +800,19 @@ parse_clientloglimit(const char *line)
/* ================================================== */ /* ================================================== */
static void
parse_makestep(const char *line)
{
if (sscanf(line, "%lf %d", &make_step_threshold, &make_step_limit) != 2) {
make_step_limit = 0;
LOG(LOGS_WARN, LOGF_Configure,
"Could not read threshold or update limit for stepping clock at line %d\n",
line_number);
}
}
/* ================================================== */
static void static void
parse_logchange(const char *line) parse_logchange(const char *line)
{ {
@@ -1319,6 +1344,15 @@ CNF_GetRTCOnUTC(void)
/* ================================================== */ /* ================================================== */
void
CNF_GetMakeStep(int *limit, double *threshold)
{
*limit = make_step_limit;
*threshold = make_step_threshold;
}
/* ================================================== */
void void
CNF_GetLogChange(int *enabled, double *threshold) CNF_GetLogChange(int *enabled, double *threshold)
{ {

1
conf.h
View File

@@ -60,6 +60,7 @@ extern int CNF_GetDumpOnExit(void);
extern int CNF_GetManualEnabled(void); extern int CNF_GetManualEnabled(void);
extern int CNF_GetCommandPort(void); extern int CNF_GetCommandPort(void);
extern int CNF_GetRTCOnUTC(void); extern int CNF_GetRTCOnUTC(void);
extern void CNF_GetMakeStep(int *limit, double *threshold);
extern void CNF_GetLogChange(int *enabled, double *threshold); extern void CNF_GetLogChange(int *enabled, double *threshold);
extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user); extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user);
extern int CNF_GetNoClientLog(void); extern int CNF_GetNoClientLog(void);

28
local.c
View File

@@ -53,7 +53,6 @@ static lcl_SetFrequencyDriver drv_set_freq;
static lcl_AccrueOffsetDriver drv_accrue_offset; static lcl_AccrueOffsetDriver drv_accrue_offset;
static lcl_ApplyStepOffsetDriver drv_apply_step_offset; static lcl_ApplyStepOffsetDriver drv_apply_step_offset;
static lcl_OffsetCorrectionDriver drv_offset_convert; static lcl_OffsetCorrectionDriver drv_offset_convert;
static lcl_ImmediateStepDriver drv_immediate_step;
static lcl_SetLeapDriver drv_set_leap; static lcl_SetLeapDriver drv_set_leap;
/* ================================================== */ /* ================================================== */
@@ -536,7 +535,6 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset, lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset, lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert, lcl_OffsetCorrectionDriver offset_convert,
lcl_ImmediateStepDriver immediate_step,
lcl_SetLeapDriver set_leap) lcl_SetLeapDriver set_leap)
{ {
drv_read_freq = read_freq; drv_read_freq = read_freq;
@@ -544,7 +542,6 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
drv_accrue_offset = accrue_offset; drv_accrue_offset = accrue_offset;
drv_apply_step_offset = apply_step_offset; drv_apply_step_offset = apply_step_offset;
drv_offset_convert = offset_convert; drv_offset_convert = offset_convert;
drv_immediate_step = immediate_step;
drv_set_leap = set_leap; drv_set_leap = set_leap;
current_freq_ppm = (*drv_read_freq)(); current_freq_ppm = (*drv_read_freq)();
@@ -558,20 +555,27 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
/* ================================================== */ /* ================================================== */
/* Look at the current difference between the system time and the NTP /* Look at the current difference between the system time and the NTP
time, and make a step to cancel it. */ time, and make a step to cancel it if it's larger than the threshold. */
int int
LCL_MakeStep(void) LCL_MakeStep(double threshold)
{ {
if (drv_immediate_step) { struct timeval raw;
(drv_immediate_step)(); double correction;
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Local, "Made step to system time to apply remaining slew");
#endif
return 1;
}
LCL_ReadRawTime(&raw);
correction = LCL_GetOffsetCorrection(&raw);
if (fabs(correction) <= threshold)
return 0; return 0;
/* Cancel remaining slew and make the step */
LCL_AccumulateOffset(correction);
LCL_ApplyStepOffset(-correction);
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.3f seconds", correction);
return 1;
} }
/* ================================================== */ /* ================================================== */

View File

@@ -179,7 +179,7 @@ extern void LCL_Finalise(void);
/* Routine to convert the outstanding system clock error to a step and /* Routine to convert the outstanding system clock error to a step and
apply it, e.g. if the system clock has ended up an hour wrong due apply it, e.g. if the system clock has ended up an hour wrong due
to a timezone problem. */ to a timezone problem. */
extern int LCL_MakeStep(void); extern int LCL_MakeStep(double threshold);
/* Routine to schedule a leap second. Leap second will be inserted /* Routine to schedule a leap second. Leap second will be inserted
at the end of the day if argument is positive, deleted if negative, at the end of the day if argument is positive, deleted if negative,

View File

@@ -56,10 +56,6 @@ typedef void (*lcl_ApplyStepOffsetDriver)(double offset);
raw time to get the corrected time */ raw time to get the corrected time */
typedef void (*lcl_OffsetCorrectionDriver)(struct timeval *raw, double *corr); typedef void (*lcl_OffsetCorrectionDriver)(struct timeval *raw, double *corr);
/* System driver to stop slewing the current offset and to apply is
as an immediate step instead */
typedef void (*lcl_ImmediateStepDriver)(void);
/* System driver to schedule leap second */ /* System driver to schedule leap second */
typedef void (*lcl_SetLeapDriver)(int leap); typedef void (*lcl_SetLeapDriver)(int leap);
@@ -71,7 +67,6 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset, lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset, lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert, lcl_OffsetCorrectionDriver offset_convert,
lcl_ImmediateStepDriver immediate_step_driver,
lcl_SetLeapDriver set_leap); lcl_SetLeapDriver set_leap);
#endif /* GOT_LOCALP_H */ #endif /* GOT_LOCALP_H */

View File

@@ -40,6 +40,8 @@ static int initialised = 0;
static int is_detached = 0; static int is_detached = 0;
static time_t last_limited = 0;
#ifdef WINNT #ifdef WINNT
static FILE *logfile; static FILE *logfile;
#endif #endif
@@ -213,6 +215,22 @@ LOG_GoDaemon(void)
#endif #endif
} }
/* ================================================== */
int
LOG_RateLimited(void)
{
time_t now;
now = time(NULL);
if (last_limited + 10 > now && last_limited <= now)
return 1;
last_limited = now;
return 0;
}
/* ================================================== */ /* ================================================== */
/* Force a core dump and exit without doing abort() or assert(0). /* Force a core dump and exit without doing abort() or assert(0).
These do funny things with the call stack in the core file that is These do funny things with the call stack in the core file that is

View File

@@ -87,6 +87,9 @@ extern void LOG_Position(const char *filename, int line_number, const char *func
extern void LOG_GoDaemon(void); extern void LOG_GoDaemon(void);
/* Return zero once per 10 seconds */
extern int LOG_RateLimited(void);
/* Line logging macro. If the compiler is GNU C, we take advantage of /* Line logging macro. If the compiler is GNU C, we take advantage of
being able to get the function name also. */ being able to get the function name also. */
#if defined(__GNUC__) #if defined(__GNUC__)

2
main.c
View File

@@ -255,7 +255,7 @@ int main
} else if (!strcmp("-6", *argv)) { } else if (!strcmp("-6", *argv)) {
DNS_SetAddressFamily(IPADDR_INET6); DNS_SetAddressFamily(IPADDR_INET6);
} else { } else {
LOG(LOGS_WARN, LOGF_Main, "Unrecognized command line option [%s]", *argv); LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
} }
} }

View File

@@ -127,33 +127,38 @@ try_again:
/* ================================================== */ /* ================================================== */
void int
DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len) DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
{ {
char *result = NULL;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
int result;
struct sockaddr_in in4; struct sockaddr_in in4;
struct sockaddr_in6 in6; struct sockaddr_in6 in6;
char hbuf[NI_MAXHOST];
switch (ip_addr->family) { switch (ip_addr->family) {
case IPADDR_INET4: case IPADDR_INET4:
memset(&in4, 0, sizeof (in4)); memset(&in4, 0, sizeof (in4));
#ifdef SIN6_LEN
in4.sin_len = sizeof (in4);
#endif
in4.sin_family = AF_INET; in4.sin_family = AF_INET;
in4.sin_addr.s_addr = htonl(ip_addr->addr.in4); in4.sin_addr.s_addr = htonl(ip_addr->addr.in4);
result = getnameinfo((const struct sockaddr *)&in4, sizeof (in4), name, len, NULL, 0, 0); if (!getnameinfo((const struct sockaddr *)&in4, sizeof (in4), hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
break; break;
case IPADDR_INET6: case IPADDR_INET6:
memset(&in6, 0, sizeof (in6)); memset(&in6, 0, sizeof (in6));
#ifdef SIN6_LEN
in6.sin6_len = sizeof (in6);
#endif
in6.sin6_family = AF_INET6; in6.sin6_family = AF_INET6;
memcpy(&in6.sin6_addr.s6_addr, ip_addr->addr.in6, sizeof (in6.sin6_addr.s6_addr)); memcpy(&in6.sin6_addr.s6_addr, ip_addr->addr.in6, sizeof (in6.sin6_addr.s6_addr));
result = getnameinfo((const struct sockaddr *)&in6, sizeof (in6), name, len, NULL, 0, 0); if (!getnameinfo((const struct sockaddr *)&in6, sizeof (in6), hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
break; break;
default:
result = 1;
} }
if (result)
snprintf(name, len, "%s", UTI_IPToString(ip_addr));
#else #else
struct hostent *host; struct hostent *host;
uint32_t addr; uint32_t addr;
@@ -171,8 +176,16 @@ DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
default: default:
host = NULL; host = NULL;
} }
snprintf(name, len, "%s", host ? host->h_name : UTI_IPToString(ip_addr)); if (host)
result = host->h_name;
#endif #endif
if (result == NULL)
result = UTI_IPToString(ip_addr);
if (snprintf(name, len, "%s", result) >= len)
return 0;
return 1;
} }
/* ================================================== */ /* ================================================== */

View File

@@ -39,7 +39,7 @@ extern void DNS_SetAddressFamily(int family);
extern int DNS_Name2IPAddress(const char *name, IPAddr *addr, int retry); extern int DNS_Name2IPAddress(const char *name, IPAddr *addr, int retry);
extern void DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len); extern int DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len);
#endif /* GOT_NAMESERV_H */ #endif /* GOT_NAMESERV_H */

View File

@@ -326,6 +326,8 @@ create_instance(NTP_Remote_Address *remote_addr, NTP_Mode mode, SourceParameters
result->local_rx.tv_usec = 0; result->local_rx.tv_usec = 0;
result->local_tx.tv_sec = 0; result->local_tx.tv_sec = 0;
result->local_tx.tv_usec = 0; result->local_tx.tv_usec = 0;
result->local_ntp_tx.hi = 0;
result->local_ntp_tx.lo = 0;
return result; return result;
@@ -1391,7 +1393,7 @@ process_known
&inst->local_ntp_tx, &inst->local_ntp_tx,
&inst->remote_addr); &inst->remote_addr);
} else { } else if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d", LOG(LOGS_WARN, LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d",
UTI_IPToString(&inst->remote_addr.ip_addr), UTI_IPToString(&inst->remote_addr.ip_addr),
inst->remote_addr.port); inst->remote_addr.port);
@@ -1559,7 +1561,7 @@ NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, NTP_Remote_Ad
remote_addr); remote_addr);
} }
} else { } else if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d", LOG(LOGS_WARN, LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d",
UTI_IPToString(&remote_addr->ip_addr), UTI_IPToString(&remote_addr->ip_addr),
remote_addr->port); remote_addr->port);

View File

@@ -460,7 +460,7 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr)
if (!cmsglen) if (!cmsglen)
msg.msg_control = NULL; msg.msg_control = NULL;
if (sendmsg(sock_fd, &msg, 0) < 0) { if (sendmsg(sock_fd, &msg, 0) < 0 && !LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_NtpIO, "Could not send to %s:%d : %s", LOG(LOGS_WARN, LOGF_NtpIO, "Could not send to %s:%d : %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, strerror(errno)); UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, strerror(errno));
} }

View File

@@ -50,6 +50,7 @@ struct MedianFilter {
int length; int length;
int index; int index;
int used; int used;
int last;
struct FilterSample *samples; struct FilterSample *samples;
}; };
@@ -57,6 +58,7 @@ struct RCL_Instance_Record {
RefclockDriver *driver; RefclockDriver *driver;
void *data; void *data;
char *driver_parameter; char *driver_parameter;
int driver_parameter_length;
int driver_poll; int driver_poll;
int driver_polled; int driver_polled;
int poll; int poll;
@@ -65,6 +67,7 @@ struct RCL_Instance_Record {
int pps_rate; int pps_rate;
struct MedianFilter filter; struct MedianFilter filter;
unsigned long ref_id; unsigned long ref_id;
unsigned long lock_ref;
double offset; double offset;
double delay; double delay;
SCH_TimeoutID timeout_id; SCH_TimeoutID timeout_id;
@@ -92,6 +95,7 @@ static void filter_init(struct MedianFilter *filter, int length);
static void filter_fini(struct MedianFilter *filter); static void filter_fini(struct MedianFilter *filter);
static void filter_reset(struct MedianFilter *filter); static void filter_reset(struct MedianFilter *filter);
static void filter_add_sample(struct MedianFilter *filter, struct timeval *sample_time, double offset); static void filter_add_sample(struct MedianFilter *filter, struct timeval *sample_time, double offset);
static int filter_get_last_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset);
static int filter_get_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset, double *dispersion); static int filter_get_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset, double *dispersion);
static void filter_slew_samples(struct MedianFilter *filter, struct timeval *when, double dfreq, double doffset); static void filter_slew_samples(struct MedianFilter *filter, struct timeval *when, double dfreq, double doffset);
@@ -166,17 +170,28 @@ RCL_AddRefclock(RefclockParameters *params)
inst->data = NULL; inst->data = NULL;
inst->driver_parameter = params->driver_parameter; inst->driver_parameter = params->driver_parameter;
inst->driver_parameter_length = 0;
inst->driver_poll = params->driver_poll; inst->driver_poll = params->driver_poll;
inst->poll = params->poll; inst->poll = params->poll;
inst->missed_samples = 0; inst->missed_samples = 0;
inst->driver_polled = 0; inst->driver_polled = 0;
inst->leap_status = 0; inst->leap_status = 0;
inst->pps_rate = params->pps_rate; inst->pps_rate = params->pps_rate;
inst->lock_ref = params->lock_ref_id;
inst->offset = params->offset; inst->offset = params->offset;
inst->delay = params->delay; inst->delay = params->delay;
inst->timeout_id = -1; inst->timeout_id = -1;
inst->source = NULL; inst->source = NULL;
if (inst->driver_parameter) {
int i;
inst->driver_parameter_length = strlen(inst->driver_parameter);
for (i = 0; i < inst->driver_parameter_length; i++)
if (inst->driver_parameter[i] == ':')
inst->driver_parameter[i] = '\0';
}
if (pps_source) { if (pps_source) {
if (inst->pps_rate < 1) if (inst->pps_rate < 1)
inst->pps_rate = 1; inst->pps_rate = 1;
@@ -216,13 +231,21 @@ RCL_AddRefclock(RefclockParameters *params)
void void
RCL_StartRefclocks(void) RCL_StartRefclocks(void)
{ {
int i; int i, j;
for (i = 0; i < n_sources; i++) { for (i = 0; i < n_sources; i++) {
RCL_Instance inst = &refclocks[i]; RCL_Instance inst = &refclocks[i];
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, NULL); inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, NULL);
inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst); inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst);
if (inst->lock_ref) {
/* Replace lock refid with index to refclocks */
for (j = 0; j < n_sources && refclocks[j].ref_id != inst->lock_ref; j++)
;
inst->lock_ref = (j < n_sources) ? j : -1;
} else
inst->lock_ref = -1;
} }
if (n_sources > 0) if (n_sources > 0)
@@ -266,6 +289,31 @@ RCL_GetDriverParameter(RCL_Instance instance)
return instance->driver_parameter; return instance->driver_parameter;
} }
char *
RCL_GetDriverOption(RCL_Instance instance, char *name)
{
char *s, *e;
int n;
s = instance->driver_parameter;
e = s + instance->driver_parameter_length;
n = strlen(name);
while (1) {
s += strlen(s) + 1;
if (s >= e)
break;
if (!strncmp(name, s, n)) {
if (s[n] == '=')
return s + n + 1;
if (s[n] == '\0')
return s + n;
}
}
return NULL;
}
int int
RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status) RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status)
{ {
@@ -313,6 +361,43 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
rate = instance->pps_rate; rate = instance->pps_rate;
assert(rate > 0); assert(rate > 0);
offset = -second - correction + instance->offset;
/* Adjust the offset to [-0.5/rate, 0.5/rate) interval */
offset -= (long)(offset * rate) / (double)rate;
if (offset < -0.5 / rate)
offset += 1.0 / rate;
else if (offset >= 0.5 / rate)
offset -= 1.0 / rate;
if (instance->lock_ref != -1) {
struct timeval ref_sample_time;
double sample_diff, ref_offset, shift;
if (!filter_get_last_sample(&refclocks[instance->lock_ref].filter,
&ref_sample_time, &ref_offset))
return 0;
UTI_DiffTimevalsToDouble(&sample_diff, &cooked_time, &ref_sample_time);
if (fabs(sample_diff) >= 2.0 / rate)
return 0;
/* Align the offset to the reference sample */
if ((ref_offset - offset) >= 0.0)
shift = (long)((ref_offset - offset) * rate + 0.5) / (double)rate;
else
shift = (long)((ref_offset - offset) * rate - 0.5) / (double)rate;
offset += shift;
if (fabs(ref_offset - offset) >= 0.2 / rate)
return 0;
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f offdiff=%.9f samplediff=%.9f",
second, offset, ref_offset - offset, sample_diff);
#endif
} else {
/* Ignore the pulse if we are not well synchronized */ /* Ignore the pulse if we are not well synchronized */
REF_GetReferenceParams(&cooked_time, &is_synchronised, &leap, &stratum, REF_GetReferenceParams(&cooked_time, &is_synchronised, &leap, &stratum,
@@ -328,19 +413,11 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
filter_reset(&instance->filter); filter_reset(&instance->filter);
return 0; return 0;
} }
}
offset = -second - correction + instance->offset;
/* Adjust the offset to [-0.5/rate, 0.5/rate) interval */
offset -= (long)(offset * rate) / (double)rate;
if (offset < -0.5 / rate)
offset += 1.0 / rate;
else if (offset >= 0.5 / rate)
offset -= 1.0 / rate;
#if 0 #if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f", LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f",
second, offset + instance->offset); second, offset);
#endif #endif
filter_add_sample(&instance->filter, &cooked_time, offset); filter_add_sample(&instance->filter, &cooked_time, offset);
@@ -511,6 +588,7 @@ filter_init(struct MedianFilter *filter, int length)
filter->length = length; filter->length = length;
filter->index = -1; filter->index = -1;
filter->used = 0; filter->used = 0;
filter->last = -1;
filter->samples = MallocArray(struct FilterSample, filter->length); filter->samples = MallocArray(struct FilterSample, filter->length);
} }
@@ -532,6 +610,7 @@ filter_add_sample(struct MedianFilter *filter, struct timeval *sample_time, doub
{ {
filter->index++; filter->index++;
filter->index %= filter->length; filter->index %= filter->length;
filter->last = filter->index;
if (filter->used < filter->length) if (filter->used < filter->length)
filter->used++; filter->used++;
@@ -539,6 +618,17 @@ filter_add_sample(struct MedianFilter *filter, struct timeval *sample_time, doub
filter->samples[filter->index].offset = offset; filter->samples[filter->index].offset = offset;
} }
static int
filter_get_last_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset)
{
if (filter->last < 0)
return 0;
*sample_time = filter->samples[filter->last].sample_time;
*offset = filter->samples[filter->last].offset;
return 1;
}
static int static int
sample_compare(const void *a, const void *b) sample_compare(const void *a, const void *b)
{ {

View File

@@ -39,6 +39,7 @@ typedef struct {
int filter_length; int filter_length;
int pps_rate; int pps_rate;
unsigned long ref_id; unsigned long ref_id;
unsigned long lock_ref_id;
double offset; double offset;
double delay; double delay;
} RefclockParameters; } RefclockParameters;
@@ -63,6 +64,7 @@ extern void RCL_CycleLogFile(void);
extern void RCL_SetDriverData(RCL_Instance instance, void *data); extern void RCL_SetDriverData(RCL_Instance instance, void *data);
extern void *RCL_GetDriverData(RCL_Instance instance); extern void *RCL_GetDriverData(RCL_Instance instance);
extern char *RCL_GetDriverParameter(RCL_Instance instance); extern char *RCL_GetDriverParameter(RCL_Instance instance);
extern char *RCL_GetDriverOption(RCL_Instance instance, char *name);
extern int RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status); extern int RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status);
extern int RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second); extern int RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second);

View File

@@ -46,15 +46,10 @@ static int pps_initialise(RCL_Instance instance) {
pps_params_t params; pps_params_t params;
struct pps_instance *pps; struct pps_instance *pps;
int fd, edge_clear, mode; int fd, edge_clear, mode;
char *path, *s; char *path;
path = RCL_GetDriverParameter(instance); path = RCL_GetDriverParameter(instance);
edge_clear = RCL_GetDriverOption(instance, "clear") ? 1 : 0;
edge_clear = 0;
if ((s = strrchr(path, ':')) != NULL) {
*s = '\0';
edge_clear = atoi(s + 1);
}
fd = open(path, O_RDWR); fd = open(path, O_RDWR);
if (fd < 0) { if (fd < 0) {

View File

@@ -56,12 +56,15 @@ struct shmTime {
}; };
static int shm_initialise(RCL_Instance instance) { static int shm_initialise(RCL_Instance instance) {
int id, param; int id, param, perm;
char *s;
struct shmTime *shm; struct shmTime *shm;
param = atoi(RCL_GetDriverParameter(instance)); param = atoi(RCL_GetDriverParameter(instance));
s = RCL_GetDriverOption(instance, "perm");
perm = s ? strtol(s, NULL, 8) & 0777 : 0600;
id = shmget(SHMKEY + param, sizeof (struct shmTime), IPC_CREAT | 0700); id = shmget(SHMKEY + param, sizeof (struct shmTime), IPC_CREAT | perm);
if (id == -1) { if (id == -1) {
LOG_FATAL(LOGF_Refclock, "shmget() failed"); LOG_FATAL(LOGF_Refclock, "shmget() failed");
return 0; return 0;

View File

@@ -61,6 +61,10 @@ static double max_update_skew;
/* Flag indicating that we are initialised */ /* Flag indicating that we are initialised */
static int initialised = 0; static int initialised = 0;
/* Threshold and update limit for stepping clock */
static int make_step_limit;
static double make_step_threshold;
/* Flag and threshold for logging clock changes to syslog */ /* Flag and threshold for logging clock changes to syslog */
static int do_log_change; static int do_log_change;
static double log_change_threshold; static double log_change_threshold;
@@ -87,9 +91,6 @@ static unsigned long logwrites = 0;
/* ================================================== */ /* ================================================== */
/* Day number of 1 Jan 1970 */
#define MJD_1970 40587
/* Reference ID supplied when we are locally referenced */ /* Reference ID supplied when we are locally referenced */
#define LOCAL_REFERENCE_ID 0x7f7f0101UL #define LOCAL_REFERENCE_ID 0x7f7f0101UL
@@ -164,6 +165,7 @@ REF_Initialise(void)
enable_local_stratum = CNF_AllowLocalReference(&local_stratum); enable_local_stratum = CNF_AllowLocalReference(&local_stratum);
CNF_GetMakeStep(&make_step_limit, &make_step_threshold);
CNF_GetLogChange(&do_log_change, &log_change_threshold); CNF_GetLogChange(&do_log_change, &log_change_threshold);
CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user); CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user);
@@ -246,7 +248,9 @@ update_drift_file(double freq_ppm, double skew)
/* Clone the file attributes from the existing file if there is one. */ /* Clone the file attributes from the existing file if there is one. */
if (!stat(drift_file,&buf)) { if (!stat(drift_file,&buf)) {
chown(temp_drift_file,buf.st_uid,buf.st_gid); if (chown(temp_drift_file,buf.st_uid,buf.st_gid)) {
LOG(LOGS_WARN, LOGF_Reference, "Could not change ownership of temporary driftfile %s.tmp", drift_file);
}
chmod(temp_drift_file,buf.st_mode&0777); chmod(temp_drift_file,buf.st_mode&0777);
} }
@@ -319,6 +323,19 @@ maybe_log_offset(double offset)
/* ================================================== */ /* ================================================== */
static void
maybe_make_step()
{
if (make_step_limit == 0) {
return;
} else if (make_step_limit > 0) {
make_step_limit--;
}
LCL_MakeStep(make_step_threshold);
}
/* ================================================== */
static void static void
update_leap_status(NTP_Leap leap) update_leap_status(NTP_Leap leap)
{ {
@@ -357,6 +374,26 @@ update_leap_status(NTP_Leap leap)
/* ================================================== */ /* ================================================== */
static void
write_log(struct timeval *ref_time, char *ref, int stratum, double freq, double skew, double offset)
{
if (logfile) {
if (((logwrites++) % 32) == 0) {
fprintf(logfile,
"=======================================================================\n"
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset\n"
"=======================================================================\n");
}
fprintf(logfile, "%s %-15s %2d %10.3f %10.3f %10.3e\n",
UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew, offset);
fflush(logfile);
}
}
/* ================================================== */
void void
REF_SetReference(int stratum, REF_SetReference(int stratum,
@@ -468,28 +505,17 @@ REF_SetReference(int stratum,
our_residual_freq = frequency; our_residual_freq = frequency;
} }
maybe_make_step();
abs_freq_ppm = LCL_ReadAbsoluteFrequency(); abs_freq_ppm = LCL_ReadAbsoluteFrequency();
if (logfile) { write_log(ref_time,
if (((logwrites++) % 32) == 0) {
fprintf(logfile,
"=======================================================================\n"
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset\n"
"=======================================================================\n");
}
fprintf(logfile, "%s %-15s %2d %10.3f %10.3f %10.3e\n",
UTI_TimeToLogForm(ref_time->tv_sec),
our_ref_ip.family != IPADDR_UNSPEC ? UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id), our_ref_ip.family != IPADDR_UNSPEC ? UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
our_stratum, our_stratum,
abs_freq_ppm, abs_freq_ppm,
1.0e6*our_skew, 1.0e6*our_skew,
our_offset); our_offset);
fflush(logfile);
}
if (drift_file) { if (drift_file) {
update_drift_file(abs_freq_ppm, our_skew); update_drift_file(abs_freq_ppm, our_skew);
} }
@@ -512,7 +538,6 @@ REF_SetManualReference
double skew double skew
) )
{ {
int millisecond;
double abs_freq_ppm; double abs_freq_ppm;
/* We are not synchronised to an external source, as such. This is /* We are not synchronised to an external source, as such. This is
@@ -525,23 +550,17 @@ REF_SetManualReference
maybe_log_offset(offset); maybe_log_offset(offset);
LCL_AccumulateFrequencyAndOffset(frequency, offset); LCL_AccumulateFrequencyAndOffset(frequency, offset);
maybe_make_step();
abs_freq_ppm = LCL_ReadAbsoluteFrequency(); abs_freq_ppm = LCL_ReadAbsoluteFrequency();
if (logfile) { write_log(ref_time,
millisecond = ref_time->tv_usec / 1000;
fprintf(logfile, "%5s %-15s %2d %10.3f %10.3f %10.3e\n",
UTI_TimeToLogForm(ref_time->tv_sec),
"127.127.1.1", "127.127.1.1",
our_stratum, our_stratum,
abs_freq_ppm, abs_freq_ppm,
1.0e6*our_skew, 1.0e6*our_skew,
our_offset); our_offset);
fflush(logfile);
}
if (drift_file) { if (drift_file) {
update_drift_file(abs_freq_ppm, our_skew); update_drift_file(abs_freq_ppm, our_skew);
} }
@@ -553,27 +572,20 @@ void
REF_SetUnsynchronised(void) REF_SetUnsynchronised(void)
{ {
/* Variables required for logging to statistics log */ /* Variables required for logging to statistics log */
int millisecond;
struct timeval now; struct timeval now;
double local_clock_err; double local_clock_err;
assert(initialised); assert(initialised);
if (logfile) {
LCL_ReadCookedTime(&now, &local_clock_err); LCL_ReadCookedTime(&now, &local_clock_err);
millisecond = now.tv_usec / 1000; write_log(&now,
fprintf(logfile, "%s %-15s 0 %10.3f %10.3f %10.3e\n",
UTI_TimeToLogForm(now.tv_sec),
"0.0.0.0", "0.0.0.0",
0,
LCL_ReadAbsoluteFrequency(), LCL_ReadAbsoluteFrequency(),
1.0e6*our_skew, 1.0e6*our_skew,
0.0); 0.0);
fflush(logfile);
}
are_we_synchronised = 0; are_we_synchronised = 0;
update_leap_status(LEAP_Unsynchronised); update_leap_status(LEAP_Unsynchronised);

View File

@@ -511,7 +511,9 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
/* Clone the file attributes from the existing file if there is one. */ /* Clone the file attributes from the existing file if there is one. */
if (!stat(coefs_file_name,&buf)) { if (!stat(coefs_file_name,&buf)) {
chown(temp_coefs_file_name,buf.st_uid,buf.st_gid); if (chown(temp_coefs_file_name,buf.st_uid,buf.st_gid)) {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not change ownership of temporary RTC file %s.tmp", coefs_file_name);
}
chmod(temp_coefs_file_name,buf.st_mode&0777); chmod(temp_coefs_file_name,buf.st_mode&0777);
} }

View File

@@ -440,7 +440,7 @@ dispatch_timeouts(struct timeval *now) {
TimerQueueEntry *ptr; TimerQueueEntry *ptr;
int n_done = 0; int n_done = 0;
while ((n_timer_queue_entries > 0) && if ((n_timer_queue_entries > 0) &&
(UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) { (UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) {
ptr = timer_queue.next; ptr = timer_queue.next;

View File

@@ -353,7 +353,9 @@ initiate_slew(void)
fast_slewing = 1; fast_slewing = 1;
slew_start_tv = T0a; slew_start_tv = T0a;
/* Set up timeout for end of slew */ /* Set up timeout for end of slew, limit to one week */
if (dseconds > 3600 * 24 * 7)
dseconds = 3600 * 24 * 7;
UTI_AddDoubleToTimeval(&T0a, dseconds, &end_of_slew); UTI_AddDoubleToTimeval(&T0a, dseconds, &end_of_slew);
slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL); slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
@@ -606,42 +608,6 @@ again:
/* ================================================== */ /* ================================================== */
static void
immediate_step(void)
{
struct timeval old_time, new_time;
struct timezone tz;
long offset;
if (fast_slewing) {
abort_slew();
}
offset = 0;
if (TMX_ApplyOffset(&offset) < 0) {
CROAK("adjtimex() failed in immediate_step");
}
offset_register -= (double) offset / 1.0e6;
slow_slewing = 0;
if (gettimeofday(&old_time, &tz) < 0) {
CROAK("gettimeofday() failed in immediate_step");
}
UTI_AddDoubleToTimeval(&old_time, -offset_register, &new_time);
if (settimeofday(&new_time, &tz) < 0) {
CROAK("settimeofday() failed in immediate_step");
}
offset_register = 0.0;
return;
}
/* ================================================== */
static void static void
set_leap(int leap) set_leap(int leap)
{ {
@@ -884,7 +850,7 @@ SYS_Linux_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency, lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset, accrue_offset, apply_step_offset,
get_offset_correction, immediate_step, set_leap); get_offset_correction, set_leap);
} }
/* ================================================== */ /* ================================================== */

View File

@@ -285,7 +285,7 @@ SYS_NetBSD_Initialise(void)
kvm_t *kt; kvm_t *kt;
FILE *fp; FILE *fp;
kt = kvm_open(NULL, NULL, NULL, O_RDWR, NULL); kt = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
if (!kt) { if (!kt) {
CROAK("Cannot open kvm\n"); CROAK("Cannot open kvm\n");
} }
@@ -299,7 +299,8 @@ SYS_NetBSD_Initialise(void)
} }
if (kvm_read(kt, nl[1].n_value, (char *)(&kern_bigadj), sizeof(long)) < 0) { if (kvm_read(kt, nl[1].n_value, (char *)(&kern_bigadj), sizeof(long)) < 0) {
CROAK("Cannot read from _bigadj\n"); /* kernel doesn't have the symbol, use one second instead */
kern_bigadj = 1000000;
} }
kvm_close(kt); kvm_close(kt);
@@ -308,7 +309,7 @@ SYS_NetBSD_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency, lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset, accrue_offset, apply_step_offset,
get_offset_correction, NULL /* immediate_step */, get_offset_correction,
NULL /* set_leap */); NULL /* set_leap */);
} }

View File

@@ -444,7 +444,7 @@ SYS_Solaris_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency, lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset, accrue_offset, apply_step_offset,
get_offset_correction, NULL /* immediate_step */, get_offset_correction,
NULL /* set_leap */); NULL /* set_leap */);
/* Turn off the kernel switch that keeps the system clock in step /* Turn off the kernel switch that keeps the system clock in step

View File

@@ -395,7 +395,7 @@ SYS_SunOS_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency, lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset, accrue_offset, apply_step_offset,
get_offset_correction, NULL /* immediate_step */, get_offset_correction,
NULL /* set_leap */); NULL /* set_leap */);
/* Turn off the kernel switch that keeps the system clock in step /* Turn off the kernel switch that keeps the system clock in step

19
util.c
View File

@@ -244,14 +244,19 @@ UTI_TimestampToString(NTP_int64 *ts)
char * char *
UTI_RefidToString(unsigned long ref_id) UTI_RefidToString(unsigned long ref_id)
{ {
unsigned int a, b, c, d; unsigned int i, j, c;
char *result; char buf[5], *result;
a = (ref_id>>24) & 0xff;
b = (ref_id>>16) & 0xff; for (i = j = 0; i < 4; i++) {
c = (ref_id>> 8) & 0xff; c = (ref_id >> (24 - i * 8)) & 0xff;
d = (ref_id>> 0) & 0xff; if (isprint(c))
buf[j++] = c;
}
buf[j] = '\0';
result = NEXT_BUFFER; result = NEXT_BUFFER;
snprintf(result, BUFFER_LENGTH, "%c%c%c%c", a, b, c, d); snprintf(result, BUFFER_LENGTH, "%s", buf);
return result; return result;
} }