Compare commits

...

206 Commits
1.25 ... 1.29.1

Author SHA1 Message Date
Miroslav Lichvar
2afdd4544d Update NEWS 2014-01-31 13:12:59 +01:00
Miroslav Lichvar
c4e61835d3 Update faq.txt 2014-01-30 15:59:45 +01:00
Miroslav Lichvar
e15ce69d08 Send cmdmon error replies only to allowed hosts
The status codes STT_BADPKTVERSION, STT_BADPKTLENGTH, STT_NOHOSTACCESS
were sent even to hosts that were not allowed by cmdallow. Deprecate
STT_NOHOSTACCESS and ignore packets from hosts not allowed by cmdallow
completely.
2014-01-30 15:59:45 +01:00
Miroslav Lichvar
d537ed11fd Support previous protocol version in chronyc
This adds compatibility with chronyd using the previous protocol version
(chrony versions 1.27, 1.28, 1.29).
2014-01-30 15:59:45 +01:00
Miroslav Lichvar
dba458d50c Add padding to cmdmon requests to prevent amplification attack
To prevent an attacker using chronyd in an amplification attack, change
the protocol to include padding in request packets so that the largest
possible reply is not larger than the request. Request packets that
don't include this padding are ignored as invalid.

This is an incompatible change in the protocol. Clients from chrony
1.27, 1.28 and 1.29 will receive NULL reply with STT_BADPKTVERSION and
print "Protocol version mismatch". Clients from 1.26 and older will not
receive a reply as it would be larger than the request if it was padded
to be compatible with their protocol.
2014-01-30 15:59:45 +01:00
Miroslav Lichvar
3e23430926 Set maximum number of samples in manual list reply to 16
In chronyd the maximum number of manual samples is 16, so there is no
need to keep room for 32 samples in the command reply. This limits the
maximum assumed size of the reply packet.
2014-01-30 15:59:45 +01:00
Miroslav Lichvar
b5658f4d9c Update NEWS 2013-08-08 15:58:07 +02:00
Miroslav Lichvar
ad58baa13b Drop support for SUBNETS_ACCESSED and CLIENT_ACCESSES commands
Support for the SUBNETS_ACCESSED and CLIENT_ACCESSES commands was
enabled in chronyd, but in chronyc it was always disabled and the
CLIENT_ACCESSES_BY_INDEX command was used instead. As there is no plan
to enable it in the future, remove the support completely.
2013-08-07 14:47:56 +02:00
Miroslav Lichvar
c6fdeeb6bb Don't send uninitialized data in command replies
The RPY_SUBNETS_ACCESSED and RPY_CLIENT_ACCESSES command replies can
contain uninitalized data from stack when the client logging is disabled
or a bad subnet is requested. These commands were never used by chronyc
and they require the client to be authenticated since version 1.25.
2013-08-07 14:46:16 +02:00
Miroslav Lichvar
7712455d9a Fix buffer overflow when processing crafted command packets
When the length of the REQ_SUBNETS_ACCESSED, REQ_CLIENT_ACCESSES
command requests and the RPY_SUBNETS_ACCESSED, RPY_CLIENT_ACCESSES,
RPY_CLIENT_ACCESSES_BY_INDEX, RPY_MANUAL_LIST command replies is
calculated, the number of items stored in the packet is not validated.

A crafted command request/reply can be used to crash the server/client.
Only clients allowed by cmdallow (by default only localhost) can crash
the server.

With chrony versions 1.25 and 1.26 this bug has a smaller security
impact as the server requires the clients to be authenticated in order
to process the subnet and client accesses commands. In 1.27 and 1.28,
however, the invalid calculated length is included also in the
authentication check which may cause another crash.
2013-08-07 13:39:02 +02:00
Miroslav Lichvar
a9a5f98406 Update chrony.conf.example2 2013-08-02 15:43:44 +02:00
Miroslav Lichvar
9ac8f64d89 Don't mention pre 2.2 Linux kernels in documentation 2013-08-02 15:43:44 +02:00
Miroslav Lichvar
0da5cf9163 Update NEWS 2013-07-17 16:19:45 +02:00
Miroslav Lichvar
f6a39d75a7 Treat address bind errors as non-fatal 2013-07-17 13:45:36 +02:00
Miroslav Lichvar
25aa9f5b42 Update chrony.spec.sample 2013-07-01 19:00:06 +02:00
Miroslav Lichvar
829b3adac3 Update copyright in chronyc GPL string 2013-07-01 17:53:27 +02:00
Miroslav Lichvar
4847a3a259 Update NEWS 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
551541d9c8 Update example config files more 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
f996f4c9fb Document port directive set to 0 as random port 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
ac78ad60f3 Use texi2html only if it's available 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
42d7cf8922 Don't ship faqgen.pl 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
e811ba7b4c Fix possible leaks of temporary file names 2013-06-21 16:09:20 +02:00
Miroslav Lichvar
cb464cac4d Fix memset calls 2013-06-21 14:39:33 +02:00
Miroslav Lichvar
fa409ddc8f Update documentation 2013-06-20 18:00:32 +02:00
Miroslav Lichvar
821226e473 Update example config files 2013-06-20 17:23:32 +02:00
Miroslav Lichvar
0e298bedf6 Create /etc and /var/lib/chrony on installation 2013-06-20 14:47:06 +02:00
Miroslav Lichvar
aa76760268 Avoid sentences written in first person 2013-06-20 13:24:24 +02:00
Miroslav Lichvar
8bf87bbfde Update comparison with ntpd 2013-06-20 13:24:24 +02:00
Miroslav Lichvar
38e889c85c Remove fixed problems from FAQ 2013-06-19 14:40:20 +02:00
Miroslav Lichvar
d5b737cce8 Update copyright years 2013-06-19 12:50:26 +02:00
Miroslav Lichvar
6ba764b5be Don't call finalise functions on fatal error
Also, return with non-zero exit code.
2013-06-19 12:28:00 +02:00
Miroslav Lichvar
707b857b68 Combine source frequencies by skew 2013-06-19 12:11:27 +02:00
Miroslav Lichvar
f8d609fee5 Add minimum skew limit to sourcestats 2013-06-19 10:22:49 +02:00
Miroslav Lichvar
01f797ac05 Fix printing of outlier status 2013-06-18 16:13:17 +02:00
Miroslav Lichvar
6fa11a853a Add more entries to tracking log
Add number of combined sources, remaining offset correction from
previous update and estimated stddev of the combined offset.
2013-06-17 18:32:16 +02:00
Miroslav Lichvar
9c78ad708b Fix maxchange offset check 2013-06-17 18:32:16 +02:00
Miroslav Lichvar
57f8160d6c Call maybe_log_offset and update_leap_status after adjusting clock 2013-06-17 18:32:16 +02:00
Miroslav Lichvar
8d80ce444f Fix spelling 2013-06-17 18:26:48 +02:00
Miroslav Lichvar
95c3acf67e Log manual entries with MANU refid in tracking log 2013-06-17 18:26:48 +02:00
Miroslav Lichvar
561f7a66dd Fix log message to not include newline 2013-06-17 18:26:48 +02:00
Miroslav Lichvar
0193688671 Fix printing of negative offset with settime command 2013-06-17 18:26:48 +02:00
Miroslav Lichvar
6d7605a3d0 Reuse REF_SetReference code with manual reference 2013-06-17 18:26:47 +02:00
Miroslav Lichvar
e0171f6e96 Write freq and skew to drift file with six decimal places 2013-06-14 19:24:03 +02:00
Miroslav Lichvar
4ef1c6f2c8 Use fscanf to read drift file 2013-06-14 19:24:03 +02:00
Miroslav Lichvar
f7e2d7c2ec Modify minimum skew checking 2013-06-14 16:27:15 +02:00
Miroslav Lichvar
3d1be1cd75 Replace bzero with memset 2013-06-14 13:48:16 +02:00
Miroslav Lichvar
2d509eb8bd Remove changelog from conf.c 2013-06-14 13:44:15 +02:00
Miroslav Lichvar
6ca73bf670 Cleanup including of system headers 2013-06-14 13:41:16 +02:00
Miroslav Lichvar
f7802f0111 Don't abort on EINTR select errors 2013-06-14 12:37:24 +02:00
Miroslav Lichvar
2f3ef235a1 Replace LOG_FATAL call with assert in SCH_MailLoop 2013-06-14 12:35:51 +02:00
Miroslav Lichvar
1ad22e9a02 Don't apply outlyer penalty at beginning
Wait until the reach register is full to allow marking a source as
outlyer for 32 updates. This makes start nicer with iburst.
2013-06-13 18:20:53 +02:00
Miroslav Lichvar
6d2fb9f782 Add minsamples and maxsamples directives
Allow configuration of the maximum and minimum number of samples per
source.
2013-06-13 16:23:32 +02:00
Miroslav Lichvar
22e5ed44c2 Modify SST_GetSelectionData to return only necessary data 2013-06-12 16:06:33 +02:00
Miroslav Lichvar
9666831818 Use UTI_DiffTimevalsToDouble to calculate theta 2013-06-12 15:30:28 +02:00
Miroslav Lichvar
ff8e04f9ba Fix fabs use on delay 2013-06-12 15:30:28 +02:00
Miroslav Lichvar
52272f4dc5 Limit sources included in combining
Combine only sources whose distance is shorter than distance of the
selected source multiplied by the value of combinelimit and their
estimated frequencies are close to the frequency of the selected source.
Add outlyer status for sources which are selectable, but not included in
the combining. The status is displayed as '-' in the chronyc sources
output.
2013-06-12 10:25:46 +02:00
Miroslav Lichvar
18a66a2ba8 Resurrect source combining
This is based on the code that was removed in CVS revision 1.3 of
sources.c. The weighting is simplified and the code is moved to a new
function.
2013-06-11 16:36:50 +02:00
Miroslav Lichvar
8aa9eb19c8 Remove unnecessary adjtimex calls 2013-06-06 19:38:36 +02:00
Miroslav Lichvar
62027f1b47 Fix rounding in UTI_AddDoubleToTimeval with negative increments 2013-06-06 16:30:37 +02:00
Miroslav Lichvar
41805d572f Adjust last_select_ts on slew 2013-06-06 16:29:50 +02:00
Miroslav Lichvar
58f768928a Rename SCH_GetFileReadyTime() and extend it to return raw time 2013-06-05 18:07:05 +02:00
Miroslav Lichvar
0074135097 Drop duplicated int64_to_timeval() 2013-06-05 13:11:53 +02:00
Miroslav Lichvar
8eb7ce8581 Fix UTI_DoubleToInt32 to check for overflow 2013-06-05 13:05:54 +02:00
Miroslav Lichvar
2ceb3c89ca Move NTP_int32 conversion functions to util.c 2013-06-05 12:49:47 +02:00
Miroslav Lichvar
d46e2a69a1 Add --enable-trace to configure 2013-06-05 12:22:07 +02:00
Miroslav Lichvar
20f9454be3 Fix configure help message 2013-06-05 11:58:13 +02:00
Miroslav Lichvar
8092366897 Abort on parse errors in refclock directive 2013-06-05 11:48:48 +02:00
Miroslav Lichvar
066254b6c8 Fix burst command with specified address
This was broken in commit 0f8def4ca4.
2013-06-05 10:39:58 +02:00
Miroslav Lichvar
79811bf3e2 Allow hostnames in offline, online and burst commands 2013-06-05 10:39:58 +02:00
Miroslav Lichvar
32bf32e7d5 Don't use uninitialized value in receive_packet() 2013-06-05 09:56:37 +02:00
Miroslav Lichvar
df968ca47c Fix stratum setting when source with non-minimum stratum is selected 2013-06-05 09:55:00 +02:00
Miroslav Lichvar
cce7a5f15e Improve peer polling in symmetric mode
If the remote stratum is higher than ours, try to lock on the peer's
polling to minimize our response time by slightly extending our delay or
waiting for the peer to catch up with us as the random part in the
actual interval is reduced. If the remote stratum is equal to ours, try
to interleave evenly with the peer.
2013-06-05 09:32:20 +02:00
Miroslav Lichvar
288043c13b Save remote poll only with valid packets 2013-06-04 15:43:59 +02:00
Miroslav Lichvar
78ae4ebfaa Fix peer polling with shorter remote poll
If the remote peer uses a polling interval shorter than the local
minimum, the local peer will be unable to send any packets as the
timeout will be updated on every received valid packet and will never
expire.

Modify the delay calculation to aim at poll interval away since the last
transmit.

Also, share the delay calculation code with transmit_timeout().
2013-06-04 12:52:49 +02:00
Miroslav Lichvar
cf700a0084 Requeue transmit timeout only with valid packets 2013-06-04 12:45:47 +02:00
Miroslav Lichvar
60a25f6e71 Ignore packets from offline sources
Rework the logic in transmit_timeout() to change the online status on
the following timeout to allow ignoring packets from offline sources.
2013-06-03 18:57:55 +02:00
Miroslav Lichvar
3eff836b2e Set stratum from last sample instead of best 2013-06-03 18:57:54 +02:00
Miroslav Lichvar
2b9fe764d5 Drop unused SST_GetReferenceData() 2013-06-03 16:03:07 +02:00
Miroslav Lichvar
030e3b2dab Make receive_packet() more readable 2013-06-03 16:03:07 +02:00
Miroslav Lichvar
5079f6bbff In burst count only accumulated samples as good 2013-06-03 16:03:07 +02:00
Miroslav Lichvar
afceb9d24e Slew only non-zero local timestamps in ntp core 2013-06-03 16:03:07 +02:00
Miroslav Lichvar
a2656a20bc Fix poll timeout with symmetric peer and poll 0 2013-06-03 16:03:05 +02:00
Miroslav Lichvar
359d444343 Remove unncessary return statements 2013-05-21 15:08:34 +02:00
Miroslav Lichvar
d510154ba2 Add recommendation on password security to keyfile description 2013-05-21 14:02:45 +02:00
Miroslav Lichvar
1c901b82dc Add option to generate command key on start
With generatecommandkey directive, if no command key is found in the key
file on start, one will be generated automatically from /dev/urandom.
2013-05-21 14:02:31 +02:00
Miroslav Lichvar
ea3672df4e Fix some error messages 2013-05-20 18:21:30 +02:00
Miroslav Lichvar
72d0b3c913 Create sockets only in selected family with -4 or -6 option 2013-05-20 15:37:25 +02:00
Miroslav Lichvar
51a2d8dfd8 Set paths in documentation by configure 2013-05-16 14:20:16 +02:00
Miroslav Lichvar
bc25380950 Document default value of commandkey 2013-05-16 14:19:03 +02:00
Miroslav Lichvar
ae1e3bf73c Add option to authenticate automatically on chronyc start 2013-05-16 14:18:57 +02:00
Miroslav Lichvar
9673a2726c Refactor key parsing 2013-05-16 14:18:33 +02:00
Miroslav Lichvar
02524397c1 Try linking readline without ncurses first 2013-05-15 11:50:58 +02:00
Joachim Wiedorn
5e5dde1a67 Various spelling fixes
Reviewed-By: Rogério Theodoro de Brito <rbrito@ime.usp.br>
2013-05-15 11:43:25 +02:00
Miroslav Lichvar
0f8def4ca4 Refactor command parsing
- normalize command line before parsing
- compare whole words
- check for missing/extra arguments in config parsing
- use strdup for string allocation
- share code for reporting syntax errors
- avoid using function pointers
- cleanup the code a bit
2013-05-15 11:27:38 +02:00
Miroslav Lichvar
182ec04e24 Abort on errors when parsing config 2013-05-15 11:14:27 +02:00
Miroslav Lichvar
ebae435398 Log online/offline status change for burst sources too. 2013-05-15 11:03:18 +02:00
Miroslav Lichvar
52657945d8 Don't send uninitialized fields in dump and local requests 2013-05-15 11:02:53 +02:00
Miroslav Lichvar
12166f8a47 Accept float value as initstepslew threshold 2013-05-14 17:16:41 +02:00
Miroslav Lichvar
c5f1dd8615 Update .gitignore 2013-05-14 17:16:41 +02:00
Miroslav Lichvar
10e67e3c1d Terminate batch processing in chronyc on quit command 2013-05-07 17:01:16 +02:00
Miroslav Lichvar
4e8ceaae86 Define DEFAULT_CONF_FILE in config.h 2013-05-07 16:35:40 +02:00
Miroslav Lichvar
73d4eaafbb Reply to NTPv1 and NTPv2 packets with same version 2013-05-02 11:10:48 +02:00
Miroslav Lichvar
cf00179964 Reply to NTPv1 packets 2013-05-02 11:10:25 +02:00
Miroslav Lichvar
edda0c60b3 Add user directive for dropping root privileges
This is equivalent to the -u option.
2013-04-26 17:38:40 +02:00
Miroslav Lichvar
f2eb6b165a Add option to ignore initstepslew and makestep directives
When chronyd is started with -R, the initstepslew directive and the
makestep directive with a positive limit will be ignored. This is useful
when restarting chronyd to avoid unnecessary clock adjustments. It can
be used with -r.
2013-04-26 17:38:37 +02:00
victor lum
4933c216b2 Fix crash with duplicated initstepslew address
When there are duplicate ntp servers listed on the initstepslew line, 2
SourceRecords are created (sourceA and sourceB), and two timers are
created (timerA and timerB).  When ntp responses are received, only
sourceA is updated because of the way read_from_socket searches for a
matching record.  Eventually, the criteria for sourceA are met, causing
timerA to stop and n_completed_sources to increment.  timerB continues
to trigger, sending ntp poll messages to the ntp server.  Responses from
that server are assigned to sourceA, triggering the criteria for sourceA
and causing n_completed_sources to increment improperly.  Once this
happens enough times, n_complete_sources == number of servers and all
SourceRecords are deleted.  The next time timerB triggers, it attempts
to access sourceB, which was already been deleted, causing the core.
2013-04-26 14:36:17 +02:00
Miroslav Lichvar
0655def57f Fix crash in config parsing with too many servers 2013-04-26 14:17:21 +02:00
Miroslav Lichvar
6eafff2450 Update URL of NTP server list in example config 2013-03-08 14:39:20 +01:00
Miroslav Lichvar
0bb772c575 Fix delta calculation with extreme frequency offsets
This should prevent chronyd from getting stuck and refusing new samples
due to failing test4 when the current measured frequency offset is close
to 1.0. That can happen when the system clock is stepped forward behind
chronyd's back.
2013-03-08 14:39:13 +01:00
Miroslav Lichvar
b261693095 Use texi2html to generate html 2013-02-01 18:40:50 +01:00
Miroslav Lichvar
129db63e30 Update NEWS 2013-02-01 15:47:43 +01:00
Miroslav Lichvar
1759d89d8a Print error message when MD5 init fails in chronyc 2013-01-24 19:04:49 +01:00
Miroslav Lichvar
0540b17fb9 Replace printf calls with echo in configure 2013-01-24 19:04:49 +01:00
Miroslav Lichvar
8893dda350 Save compiler messages to config.log in configure 2013-01-24 18:57:39 +01:00
Miroslav Lichvar
b14689d59b Fix crash and hangs in RGR_FindBestRobustRegression 2012-11-29 16:23:22 +01:00
Miroslav Lichvar
1ca844af98 Check for errors when writing new drift files 2012-09-10 17:31:56 +02:00
Miroslav Lichvar
3059747c35 Add format string to printf in client.c 2012-09-10 17:31:56 +02:00
Miroslav Lichvar
bbbb3633a7 Add support for nanoseconds in SHM 2012-09-10 17:31:56 +02:00
Miroslav Lichvar
df6c2a432f Fuzz transmit timestamp
Add random bits below clock precision to the timestamp to make
it less predictable.
2012-05-23 12:06:16 +02:00
Miroslav Lichvar
d0acfc2652 Log uncooked offset in refclocks log for PPS samples 2012-03-13 13:17:03 +01:00
Miroslav Lichvar
711cda6aed Update NEWS 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
0c738d84af Update copyright years 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
be1e1dc441 Fix password handling in chronyc 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
2a305d8e16 Fix compiler warnings 2012-02-27 16:08:21 +01:00
Miroslav Lichvar
15b6ab77ea Update configure help text 2012-02-27 15:45:27 +01:00
Miroslav Lichvar
6199822783 Test leap second timezone on start 2012-02-27 13:28:14 +01:00
Miroslav Lichvar
0b72b2940a Update documentation 2012-02-27 13:28:14 +01:00
Miroslav Lichvar
d4ce3f19c3 Reschedule fast slew timeout on offset change 2012-02-24 16:26:53 +01:00
Miroslav Lichvar
824e86a82f Add leap status to tracking log and report 2012-02-24 11:06:20 +01:00
Miroslav Lichvar
2a5c045c3d Add support for reading leap second data from tz database
leapsectz directive is used to set the name of the timezone in the
system tz database which chronyd can use to find out when will the next
leap second occur.  It will periodically check if dates Jun 30 23:59:60
and Dec 31 23:59:60 are valid in that timezone. This is mainly useful
with reference clocks which don't provide the leap second information.
It is not necessary to restart chronyd if the tz database is updated
with a new leap second at least 12 hours before the event.
2012-02-24 11:06:20 +01:00
Miroslav Lichvar
f7c65a4b88 Add maxchange directive
This directive sets the maximum allowed offset corrected on a clock
update.  The check is performed only after the specified number of
updates to allow a large initial adjustment of the system clock.  When
an offset larger than the specified maximum occurs, it will be ignored
for the specified number of times and then chronyd will give up
and exit (a negative value can be used to never exit).  In both cases
a message is sent to syslog.
2012-02-21 14:34:09 +01:00
Miroslav Lichvar
a8956f2f56 Move refclock slew and dispersion handler init 2012-02-14 18:13:15 +01:00
Miroslav Lichvar
91c9f84a01 Step system time in RTC preinit only with offsets over 1 second 2012-02-14 17:49:55 +01:00
Miroslav Lichvar
2be89bc6f2 Fix last commit 2012-02-14 14:47:57 +01:00
Miroslav Lichvar
d6c447a445 Better estimate RTC offset right after trim 2012-02-13 16:54:18 +01:00
Miroslav Lichvar
a60586eaad Return success on empty command 2012-02-10 18:30:11 +01:00
Miroslav Lichvar
d77356837a Support passwords encoded in HEX 2012-02-09 16:56:17 +01:00
Miroslav Lichvar
d6842301dd Update reported RMS offset quickly on start 2012-02-08 14:30:35 +01:00
Miroslav Lichvar
19b3c5be26 Extend tracking, sources and activity reports 2012-02-03 17:22:53 +01:00
Miroslav Lichvar
5fb5a89f02 Use +/- when logging skew on start 2012-02-03 17:22:52 +01:00
Miroslav Lichvar
9367e7b9af Fix logged offset in manual reference 2012-02-03 15:23:25 +01:00
Miroslav Lichvar
6673cadfa2 Check if struct in6_pktinfo is usable 2012-01-05 15:11:54 +01:00
Miroslav Lichvar
b485051b65 Fix reported number of runs to correspond to reported number of samples 2011-11-28 11:19:48 +01:00
Miroslav Lichvar
9a01ccc07f Add corrtimeratio directive
The corrtimeratio directive controls the ratio between the
duration in which the clock is slewed for an average correction
according to the source history and the interval in which the
corrections are done (usually the NTP polling interval).  Corrections
larger than the average take less time and smaller corrections take
more time, the amount of the correction and the correction time are
inversely proportional.

Increasing corrtimeratio makes the overall frequency error of
the system clock smaller, but increases the overall time error as
the corrections will take longer.

By default, the ratio is 1, which means the duration of an average
correction will be close to the update interval.
2011-11-15 18:25:49 +01:00
Miroslav Lichvar
1b8deaf354 Control offset correction rate in Linux driver
The kernel currently doesn't support a linear adjustment with
programmable rate, extend the use of the kernel PLL with locked
frequency instead.

Set the PLL time constant according to the correction time corresponding
to the correction rate and corrected offset.

On kernels with nano PLL adjtime() is no longer used.
2011-11-15 12:30:59 +01:00
Miroslav Lichvar
c7d0232bb1 Introduce offset correction rate
We want to correct the offset quickly, but we also want to keep the
frequency error caused by the correction itself low.

Define correction rate as the area of the region bounded by the graph of
offset corrected in time. Set the rate so that the time needed to correct
an offset equal to the current sourcestats stddev will be equal to the
update interval (assuming linear adjustment). The offset and the
time needed to make the correction are inversely proportional.

This is only a suggestion and it's up to the system driver how the
adjustment will be executed.
2011-11-15 12:27:44 +01:00
Miroslav Lichvar
79e5f2be13 Include clock steps in calculated reference update interval 2011-11-14 15:55:19 +01:00
Miroslav Lichvar
9ab181eb9c Document extended keyfile format and authhash command 2011-11-02 13:53:00 +01:00
Miroslav Lichvar
3cc6021e03 Add support for libtomcrypt 2011-11-02 13:53:00 +01:00
Miroslav Lichvar
375389fa1e Add support for NSS library
This adds support for the NSSLOWHASH API provided by the freebl3
library.
2011-11-02 13:53:00 +01:00
Miroslav Lichvar
777303f130 Add support for different authentication hashes
Allow different hash functions to be used in the NTP and cmdmon
protocols. This breaks the cmdmon protocol compatibility. Extended key
file format is used to specify the hash functions for chronyd and new
authhash command is added to chronyc. MD5 is the default and the only
function included in the chrony source code, other functions will be
available from libraries.
2011-11-02 13:53:00 +01:00
Miroslav Lichvar
6015f99d98 Fix writing rtc data when called soon after trimrtc 2011-09-14 18:03:01 +02:00
Miroslav Lichvar
78fc17c661 Use ADJ_OFFSET_SS_READ mode only with kernels 2.6.28 and later 2011-09-13 16:39:08 +02:00
Miroslav Lichvar
d42addf746 Add macro for maximum fastslew timeout 2011-09-01 18:08:45 +02:00
Miroslav Lichvar
f570eb76b3 Check for timepps.h also in sys directory 2011-09-01 17:06:54 +02:00
Miroslav Lichvar
cc3f5962b8 Merge NCR_Process functions 2011-09-01 16:25:13 +02:00
Miroslav Lichvar
6ab3d1daa3 Add support for ADJ_SETOFFSET mode
This adjtimex mode allows precise stepping of the system clock.
2011-09-01 15:31:11 +02:00
Miroslav Lichvar
b088b70f82 Check sample ordering on accumulation
If the newly accumulated sample is not newer than than the last one,
discard the source history and start from scratch. This can happen after
loading an invalid dump or when the system clock was stepped.
2011-08-31 18:36:10 +02:00
Miroslav Lichvar
fbbb6bbc00 Update gpsd SOCK example in documentation 2011-08-26 18:34:00 +02:00
Miroslav Lichvar
5c36342958 Use initial delay also for burst samples 2011-08-26 18:34:00 +02:00
Miroslav Lichvar
f1a0cacc5a Make scheduling loop detector less sensitive
It could be triggered by delayed name resolving as it adds multiple new
timeouts which can be called in the same dispatching if the DNS responses
are slower than initial delay and sampling separation.

Compare number of dispatched events also with current number of
timeouts.
2011-08-26 18:34:00 +02:00
Miroslav Lichvar
1d2a0856b4 Wait in foreground process until daemon is fully initialized
Exit when all sockets are ready and initstepslew command and rtc step
are completed. Also, in case of a fatal error, print the error message
and exit with a non-zero status.
2011-08-26 18:31:26 +02:00
Miroslav Lichvar
7fb50d9a3e Always use delayed name resolving for server and peer directives
This significantly reduces initialization time.
2011-08-26 14:22:10 +02:00
Miroslav Lichvar
919b5b5a7d Change working directory to / 2011-08-25 18:49:34 +02:00
Miroslav Lichvar
1e35b26826 Read config after opening syslog 2011-08-25 14:46:16 +02:00
Miroslav Lichvar
27b0b5824a Disable maxdelayratio test by default
Change default maxdelayratio from 16384.0 to 0.0. A value larger
than 1.0 is required to enable the test.
2011-08-12 15:38:05 +02:00
Miroslav Lichvar
1d72d22bc5 Match skew in ntp_core to sourcestats skew 2011-08-12 15:38:05 +02:00
Miroslav Lichvar
e0c9ed44f9 Limit skew used in NTP test4
With iburst and very jittery sources the source skew can reach very high
values which makes the NTP test4 fail even with relatively small delays.
Limit the skew to 2000 ppm to avoid getting state where a source is unable
to accept more than first three iburst samples.
2011-08-12 15:37:58 +02:00
Miroslav Lichvar
411f4da340 Fix creating logdir 2011-08-11 14:15:15 +02:00
Miroslav Lichvar
4fac84098e Update NEWS 2011-07-13 14:55:28 +02:00
Miroslav Lichvar
21b2063a6f Retry on permanent DNS error by default 2011-07-13 14:49:22 +02:00
Miroslav Lichvar
917c191650 Update NEWS 2011-06-24 13:45:16 +02:00
Miroslav Lichvar
2bfce03d29 Add configure option for sendmail path 2011-06-24 13:27:30 +02:00
Miroslav Lichvar
1cb8167be0 Generate version and date in man pages 2011-06-24 12:30:48 +02:00
Miroslav Lichvar
40d33cc64d Convert make_release to shell script 2011-06-24 12:27:54 +02:00
Miroslav Lichvar
95433e9639 Remove chrony.lsm 2011-06-23 17:49:18 +02:00
Miroslav Lichvar
bbe1a09e7e Step also cooked select timestamp in scheduler slew handler 2011-06-23 15:23:16 +02:00
Miroslav Lichvar
dce2366b3a Detect infinite loop in scheduler
If more timeouts were handled than there were in the timer queue on
start, assume some code is scheduling timeouts with negative delays and
abort. Make the actual limit higher in case the machine is temporarily
overloaded and dispatching the handlers takes more time than was delay
of a scheduled timeout.
2011-06-23 15:14:08 +02:00
Miroslav Lichvar
bab7ba22cf Add asserts for timeout delays 2011-06-23 13:42:04 +02:00
Miroslav Lichvar
d6a91057ae Add waitsync command 2011-06-23 12:13:51 +02:00
Miroslav Lichvar
c6e9065498 Fix current_total_tick calculation 2011-06-15 15:35:15 +02:00
Miroslav Lichvar
22fda21eae Don't call driver read_freq in LCL_ReadAbsoluteFrequency 2011-06-15 15:35:14 +02:00
Miroslav Lichvar
103a520aa6 Create logdir before making first tracking write 2011-06-15 15:35:14 +02:00
Miroslav Lichvar
86531a51a7 Don't update drift file on first reference update 2011-06-15 15:35:14 +02:00
Miroslav Lichvar
2b7e4d645f Don't reset kernel frequency on start without drift file 2011-06-15 15:35:00 +02:00
Miroslav Lichvar
a5f63180fc Don't use uninitialized values 2011-06-13 18:17:33 +02:00
Miroslav Lichvar
934d4e04b5 Validate leap status in refclock samples 2011-06-13 17:03:30 +02:00
Miroslav Lichvar
1b8547059a Set leap status by enum 2011-06-13 17:02:42 +02:00
Miroslav Lichvar
91279a0f28 Store reference IDs in uint32_t 2011-06-13 15:34:16 +02:00
Miroslav Lichvar
31ba3144c8 Don't limit refclock driver name to 4 chars 2011-06-13 13:49:46 +02:00
Miroslav Lichvar
0bf34725e3 Don't try to recover from our own time steps 2011-06-10 18:57:04 +02:00
Miroslav Lichvar
91749ebb2b Try to handle unexpected backward time jumps 2011-06-10 18:29:41 +02:00
Miroslav Lichvar
4ba3dd66ad Set version string in config.h 2011-06-09 14:32:22 +02:00
Miroslav Lichvar
d40696f7f3 Add .deps to .gitignore 2011-06-09 14:31:04 +02:00
Miroslav Lichvar
4a401a9e83 Make .deps order-only prerequisite 2011-06-09 13:56:45 +02:00
Miroslav Lichvar
6a2a837ede Remove kernel version check from rtc code
It should work with all currently supported kernels (>= 2.2.0).
2011-06-06 21:33:59 +02:00
Miroslav Lichvar
eca08a281c Determine hz and shift from sysconf(_SC_CLK_TCK) when available 2011-06-06 17:41:14 +02:00
Miroslav Lichvar
9fd8f76fa0 Log final version specific details 2011-06-06 17:12:31 +02:00
Miroslav Lichvar
50de930730 Drop support for old readonly adjtime 2011-06-06 17:12:31 +02:00
Miroslav Lichvar
da1097095c Drop support for pre 2.2 Linux kernels 2011-06-06 17:12:31 +02:00
Miroslav Lichvar
ec7d302a6c Support Linux 3.0 and later 2011-06-06 13:56:27 +02:00
Miroslav Lichvar
8cc7ebffa9 Accept packets with compatible NTP versions
All incoming NTP packets are now required to have version 2, 3 or 4.
2011-05-25 16:59:40 +02:00
Miroslav Lichvar
de4d14843f Set source IPv6 address on NTP reply
This is needed on systems with multiple IPv6 addresses to reply with
the same source address as the destination address of the NTP request.
2011-05-24 18:07:06 +02:00
Miroslav Lichvar
18605795a7 Merge CCWARNFLAGS with CFLAGS 2011-05-24 18:07:06 +02:00
Miroslav Lichvar
da2c8d9076 Use config.h 2011-05-24 18:07:06 +02:00
Miroslav Lichvar
3120f8adb6 Use object dependencies in Makefile 2011-05-24 18:06:49 +02:00
93 changed files with 5024 additions and 3471 deletions

15
.gitignore vendored
View File

@@ -1,6 +1,19 @@
*.swp
.deps
.vimrc
*.o
*.swp
RELEASES
Makefile
chrony.conf.5
chrony.info
chrony.html
chrony.texi
chrony.txt
chronyc
chronyc.1
chronyd
chronyd.8
config.h
config.log
tags
version.h

12
INSTALL
View File

@@ -81,12 +81,14 @@ Now that the software is successfully installed, the next step is to
set up a configuration file. The contents of this depend on the
network environment in which the computer operates. Typical scenarios
are described in the manual. The simplest case is for a computer with
a permanent Internet connection - suppose you want to use the NTP
server ntp1.foobar.com as your time reference. You would create an
/etc/chrony.conf file containing
a permanent Internet connection - suppose you want to use public NTP
servers from the pool.ntp.org project as your time reference. You would
create an /etc/chrony.conf file containing
server ntp1.foobar.com
driftfile /etc/chrony.drift
server 0.pool.ntp.org
server 1.pool.ntp.org
server 2.pool.ntp.org
driftfile /var/lib/chrony/drift
and then run /usr/local/sbin/chronyd.

View File

@@ -27,32 +27,32 @@ SBINDIR=@SBINDIR@
MANDIR=@MANDIR@
INFODIR=@INFODIR@
DOCDIR=@DOCDIR@
LOCALSTATEDIR=@LOCALSTATEDIR@
CHRONYVARDIR=@CHRONYVARDIR@
CC = @CC@
CCWARNFLAGS = @CCWARNFLAGS@
OPTFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@ @SYSDEFS@ @EXTRA_DEFS@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
DESTDIR=
HASH_OBJ = @HASH_OBJ@
OBJS = util.o sched.o regress.o local.o \
sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \
sources.o sourcestats.o reference.o \
logging.o conf.o cmdmon.o md5.o keys.o \
logging.o conf.o cmdmon.o keys.o \
nameserv.o acquire.o manual.o addrfilt.o \
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
broadcast.o refclock.o refclock_shm.o refclock_sock.o \
refclock_pps.o tempcomp.o
refclock_pps.o tempcomp.o $(HASH_OBJ)
EXTRA_OBJS=@EXTRA_OBJECTS@
CLI_OBJS = client.o md5.o nameserv.o getdate.o cmdparse.o \
pktlength.o util.o
CLI_OBJS = client.o nameserv.o getdate.o cmdparse.o \
pktlength.o util.o $(HASH_OBJ)
SRCS = $(patsubst %.o,%.c,$(OBJS))
EXTRA_SRCS = $(patsubst %.o,%.c,$(EXTRA_OBJS))
CLI_SRCS = $(patsubst %.o,%.c,$(CLI_OBJS))
ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS)
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
@@ -60,36 +60,30 @@ LIBS = @LIBS@
EXTRA_LIBS=@EXTRA_LIBS@
EXTRA_CLI_LIBS=@EXTRA_CLI_LIBS@
CFLAGS = $(CCWARNFLAGS) $(OPTFLAGS)
# Until we have a main procedure we can link, just build object files
# to test compilation
all : chronyd chronyc
chronyd : $(OBJS) $(EXTRA_OBJS)
$(CC) $(OPTFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS)
$(CC) $(CFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) @HASH_LINK@ $(LIBS) $(EXTRA_LIBS)
chronyc : $(CLI_OBJS)
$(CC) $(OPTFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) @READLINE_LINK@ $(LIBS) $(EXTRA_CLI_LIBS)
conf.o : conf.c
$(CC) $(CFLAGS) $(CPPFLAGS) -DDEFAULT_CONF_DIR=\"$(SYSCONFDIR)\" -c $<
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) @READLINE_LINK@ @HASH_LINK@ $(LIBS) $(EXTRA_CLI_LIBS)
client.o : client.c
$(CC) $(CFLAGS) $(CPPFLAGS) @READLINE_COMPILE@ -c $<
.depend :
gcc -MM $(SRCS) $(EXTRA_SRCS) > .depend
$(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
distclean :
-rm -f *.o *.s chronyc chronyd core options.h Makefile *~
distclean : clean
-rm -f Makefile
-rm -f chrony.conf.5 chrony.texi chronyc.1 chronyd.8
clean :
-rm -f *.o *.s chronyc chronyd core *~
version.h : version.txt
./mkversion
-rm -f *.o *.s chronyc chronyd core *~ chrony.info chrony.html chrony.txt
-rm -rf .deps
getdate.c : ;
getdate :
@@ -99,6 +93,7 @@ getdate :
# seem to vary between systems.
install: chronyd chronyc
[ -d $(DESTDIR)$(SYSCONFDIR) ] || mkdir -p $(DESTDIR)$(SYSCONFDIR)
[ -d $(DESTDIR)$(SBINDIR) ] || mkdir -p $(DESTDIR)$(SBINDIR)
[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
@@ -106,6 +101,7 @@ install: chronyd chronyc
[ -d $(DESTDIR)$(MANDIR)/man5 ] || mkdir -p $(DESTDIR)$(MANDIR)/man5
[ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
[ -d $(DESTDIR)$(CHRONYVARDIR) ] || mkdir -p $(DESTDIR)$(CHRONYVARDIR)
if [ -f $(DESTDIR)$(SBINDIR)/chronyd ]; then rm -f $(DESTDIR)$(SBINDIR)/chronyd ; fi
if [ -f $(DESTDIR)$(BINDIR)/chronyc ]; then rm -f $(DESTDIR)$(BINDIR)/chronyc ; fi
cp chronyd $(DESTDIR)$(SBINDIR)/chronyd
@@ -133,11 +129,6 @@ install: chronyd chronyc
%.s : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -S $<
main.o logging.o client.o : version.h
# makeinfo v4 required to generate plain text and html
MAKEINFO:=makeinfo
install-docs : docs
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
cp chrony.txt $(DESTDIR)$(DOCDIR)/chrony.txt
@@ -151,15 +142,23 @@ install-docs : docs
docs : chrony.txt chrony.html chrony.info
chrony.txt : chrony.texi
$(MAKEINFO) --no-headers --number-sections -o chrony.txt chrony.texi
makeinfo --no-headers --number-sections -o chrony.txt chrony.texi
chrony.html : chrony.texi
$(MAKEINFO) --no-split --html --number-sections -o chrony.html chrony.texi
command -v texi2html > /dev/null 2>&1 && texi2html chrony.texi || \
makeinfo --no-split --html --number-sections -o chrony.html chrony.texi
chrony.info : chrony.texi
$(MAKEINFO) chrony.texi
makeinfo chrony.texi
# This is only relevant if you're maintaining the website!
faq.php : faq.txt faqgen.pl
perl faqgen.pl < faq.txt > faq.php
.deps:
@mkdir .deps
.deps/%.d: %.c | .deps
@$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@
-include $(ALL_OBJS:%.o=.deps/%.d)

75
NEWS
View File

@@ -1,3 +1,78 @@
New in version 1.29.1
=====================
Security fixes
--------------
* Modify chronyc protocol to prevent amplification attacks (CVE-2014-0021)
(incompatible with previous protocol version, chronyc supports both)
New in version 1.29
===================
Security fixes
--------------
* Fix crash when processing crafted commands (CVE-2012-4502)
(possible with IP addresses allowed by cmdallow and localhost)
* Don't send uninitialized data in SUBNETS_ACCESSED and CLIENT_ACCESSES
replies (CVE-2012-4503) (not used by chronyc)
Other changes
-------------
* Drop support for SUBNETS_ACCESSED and CLIENT_ACCESSES commands
New in version 1.28
===================
* Combine sources to improve accuracy
* Make config and command parser strict
* Add -a option to chronyc to authenticate automatically
* Add -R option to ignore initstepslew and makestep directives
* Add generatecommandkey, minsamples, maxsamples and user directives
* Improve compatibility with NTPv1 and NTPv2 clients
* Create sockets only in selected family with -4/-6 option
* Treat address bind errors as non-fatal
* Extend tracking log
* Accept float values as initstepslew threshold
* Allow hostnames in offline, online and burst commands
* Fix and improve peer polling
* Fix crash in config parsing with too many servers
* Fix crash with duplicated initstepslew address
* Fix delta calculation with extreme frequency offsets
* Set local stratum correctly
* Remove unnecessary adjtimex calls
* Set paths in documentation by configure
* Update chrony.spec
New in version 1.27
===================
* Support for stronger keys via NSS or libtomcrypt library
* Support reading leap second data from tz database
* Support for precise clock stepping on Linux
* Support for nanoseconds in SHM refclock
* Make offset corrections smoother on Linux
* Make transmit timestamps random below clock precision
* Add corrtimeratio and maxchange directives
* Extend tracking, sources and activity reports
* Wait in foreground process until daemon is fully initialized
* Fix crash with slow name resolving
* Fix iburst with jittery sources
* Fix offset stored in rtc data right after trimrtc
* Fix crash and hang with RTC or manual samples
* Don't use readonly adjtime on Linux kernels before 2.6.28
* Changed chronyc protocol, incompatible with older versions
New in version 1.26
===================
* Add compatibility with Linux 3.0 and later
* Use proper source address in NTP replies on multihomed IPv6 hosts
* Accept NTP packets with versions 4, 3 and 2
* Cope with unexpected backward time jumps
* Don't reset kernel frequency on start without drift file
* Retry on permanent DNS error by default
* Add waitsync command
New in version 1.25
===================

21
README
View File

@@ -10,7 +10,7 @@ time. This does most of the work.
chronyc is a command-line interface program which can be used to
monitor chronyd's performance and to change various operating
parateters whilst it is running.
parameters whilst it is running.
chronyd's main function is to obtain measurements of the true (UTC)
time from one of several sources, and correct the system clock
@@ -21,12 +21,12 @@ between measurements from the reference.
The reference time can be derived from Network Time Protocol (NTP)
servers, reference clocks, or wristwatch-and-keyboard (via chronyc).
The main source of information about the Network Time Protocol is
http://www.eecis.udel.edu/~ntp.
http://www.ntp.org.
It is designed so that it can work on computers which only have
intermittent access to reference sources, for example computers which
use a dial-up account to access the Internet. Of course, it will work
on computers with permanent connections too.
use a dial-up account to access the Internet or laptops. Of course, it
will work well on computers with permanent connections too.
In addition, on Linux it can monitor the system's real time clock
performance, so the system can maintain accurate time even across
@@ -48,10 +48,7 @@ What will chrony run on?
Chrony can be successfully built and run on
1. Linux v1.2.13, v2.0.x, 2.1.x (partially), 2.2.x, 2.3.x, 2.4.x, 2.6.x.
Real time clock support is limited to 2.0.32 onwards and to 2.2, 2.3,
2.4 and 2.6 series only. i386, x86_64, PowerPC are known to be
supported.
1. Linux 2.2.x, 2.3.x, 2.4.x, 2.6.x, 3.x
2. Solaris 2.5/2.5.1/2.6/2.7/2.8 (various platforms)
@@ -88,12 +85,6 @@ through the URL
http://chrony.tuxfamily.org/
What can chrony not do?
=======================
Compared to the `reference' RFC1305 implementation xntpd, chronyd does
not support broadcast modes.
Where are new versions announced?
=================================
@@ -252,5 +243,3 @@ Doug Woodward <dougw@whistler.com>
Many other people have contributed bug reports and suggestions. I'm
sorry I can't identify all of you individually.
vim:tw=72

View File

@@ -37,6 +37,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "acquire.h"
@@ -61,6 +63,10 @@
#define RETRANSMISSION_TIMEOUT (1.0)
#define NTP_VERSION 3
#define NTP_MAX_COMPAT_VERSION 4
#define NTP_MIN_COMPAT_VERSION 2
typedef struct {
IPAddr ip_addr; /* Address of the server */
int sanity; /* Flag indicating whether source
@@ -88,7 +94,7 @@ static int n_sources;
static int n_started_sources;
static int n_completed_sources;
static int init_slew_threshold = -1;
static double init_slew_threshold;
union sockaddr_in46 {
struct sockaddr_in in4;
@@ -137,7 +143,6 @@ static SCH_TimeoutID source_start_timeout_id;
void
ACQ_Initialise(void)
{
return;
}
@@ -146,7 +151,6 @@ ACQ_Initialise(void)
void
ACQ_Finalise(void)
{
return;
}
/* ================================================== */
@@ -195,7 +199,7 @@ prepare_socket(int family)
}
if (bind(sock_fd, &my_addr.u, addrlen) < 0) {
LOG(LOGS_ERR, LOGF_Acquire, "Could not bind socket : %s\n", strerror(errno));
LOG(LOGS_ERR, LOGF_Acquire, "Could not bind socket : %s", strerror(errno));
/* but keep running */
}
}
@@ -234,8 +238,6 @@ finalise_io(void)
}
sock_fd6 = -1;
#endif
return;
}
/* ================================================== */
@@ -244,12 +246,13 @@ static void
probe_source(SourceRecord *src)
{
NTP_Packet pkt;
int version = 3;
int version = NTP_VERSION;
NTP_Mode my_mode = MODE_CLIENT;
struct timeval cooked;
union sockaddr_in46 his_addr;
int sock_fd;
socklen_t addrlen;
uint32_t ts_fuzz;
#if 0
printf("Sending probe to %s sent=%d samples=%d\n", UTI_IPToString(&src->ip_addr), src->n_probes_sent, src->n_samples);
@@ -262,9 +265,9 @@ probe_source(SourceRecord *src)
pkt.stratum = 0;
pkt.poll = 4;
pkt.precision = -6; /* as ntpdate */
pkt.root_delay = double_to_int32(1.0); /* 1 second */
pkt.root_dispersion = double_to_int32(1.0); /* likewise */
pkt.reference_id = 0UL;
pkt.root_delay = UTI_DoubleToInt32(1.0); /* 1 second */
pkt.root_dispersion = UTI_DoubleToInt32(1.0); /* likewise */
pkt.reference_id = 0;
pkt.reference_ts.hi = 0; /* Set to 0 */
pkt.reference_ts.lo = 0; /* Set to 0 */
pkt.originate_ts.hi = 0; /* Set to 0 */
@@ -298,8 +301,9 @@ probe_source(SourceRecord *src)
}
ts_fuzz = UTI_GetNTPTsFuzz(LCL_GetSysPrecisionAsLog());
LCL_ReadCookedTime(&cooked, NULL);
UTI_TimevalToInt64(&cooked, &pkt.transmit_ts);
UTI_TimevalToInt64(&cooked, &pkt.transmit_ts, ts_fuzz);
if (sendto(sock_fd, (void *) &pkt, NTP_NORMAL_PACKET_SIZE,
0,
@@ -314,8 +318,6 @@ probe_source(SourceRecord *src)
++(src->n_dead_probes);
src->timer_running = 1;
src->timeout_id = SCH_AddTimeoutByDelay(RETRANSMISSION_TIMEOUT, transmit_timeout, (void *) src);
return;
}
/* ================================================== */
@@ -370,7 +372,7 @@ process_receive(NTP_Packet *msg, SourceRecord *src, struct timeval *now)
mode = lvm & 0x7;
if ((leap == LEAP_Unsynchronised) ||
(version != 3) ||
(version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) ||
(mode != MODE_SERVER && mode != MODE_PASSIVE)) {
return;
}
@@ -391,8 +393,8 @@ process_receive(NTP_Packet *msg, SourceRecord *src, struct timeval *now)
return;
}
root_delay = int32_to_double(msg->root_delay);
root_dispersion = int32_to_double(msg->root_dispersion);
root_delay = UTI_Int32ToDouble(msg->root_delay);
root_dispersion = UTI_Int32ToDouble(msg->root_dispersion);
UTI_Int64ToTimeval(&src->last_tx, &local_orig);
UTI_Int64ToTimeval(&msg->receive_ts, &remote_rx);
@@ -447,7 +449,7 @@ read_from_socket(void *anything)
his_addr_len = sizeof(his_addr);
/* Get timestamp */
SCH_GetFileReadyTime(&now, NULL);
SCH_GetLastEventTime(&now, NULL, NULL);
sock_fd = (long)anything;
status = recvfrom (sock_fd, (char *)&msg, message_length, flags,
@@ -693,7 +695,7 @@ process_measurements(void)
the system clock is fast of the reference, i.e. it needs to be
stepped backwards. */
if (fabs(estimated_offset) > (double) init_slew_threshold) {
if (fabs(estimated_offset) > init_slew_threshold) {
LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (step)",
fabs(estimated_offset),
(estimated_offset >= 0) ? "fast" : "slow");
@@ -702,7 +704,7 @@ process_measurements(void)
LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (slew)",
fabs(estimated_offset),
(estimated_offset >= 0) ? "fast" : "slow");
LCL_AccumulateOffset(estimated_offset);
LCL_AccumulateOffset(estimated_offset, 0.0);
}
} else {
@@ -745,10 +747,11 @@ start_source_timeout_handler(void *not_used)
/* ================================================== */
void
ACQ_StartAcquisition(int n, IPAddr *ip_addrs, int threshold, void (*after_hook)(void *), void *anything)
ACQ_StartAcquisition(int n, IPAddr *ip_addrs, double threshold, void (*after_hook)(void *), void *anything)
{
int i, ip4, ip6;
int k, duplicate_ip;
saved_after_hook = after_hook;
saved_after_hook_anything = anything;
@@ -757,26 +760,37 @@ ACQ_StartAcquisition(int n, IPAddr *ip_addrs, int threshold, void (*after_hook)(
n_started_sources = 0;
n_completed_sources = 0;
n_sources = n;
n_sources = 0;
sources = MallocArray(SourceRecord, n);
for (i = ip4 = ip6 = 0; i < n; i++) {
sources[i].ip_addr = ip_addrs[i];
sources[i].n_samples = 0;
sources[i].n_total_samples = 0;
sources[i].n_dead_probes = 0;
if (ip_addrs[i].family == IPADDR_INET4)
ip4++;
else if (ip_addrs[i].family == IPADDR_INET6)
ip6++;
/* check for duplicate IP addresses and ignore them */
duplicate_ip = 0;
for (k = 0; k < i; k++) {
duplicate_ip |= UTI_CompareIPs(&(sources[k].ip_addr),
&ip_addrs[i],
NULL) == 0;
}
if (!duplicate_ip) {
sources[n_sources].ip_addr = ip_addrs[i];
sources[n_sources].n_samples = 0;
sources[n_sources].n_total_samples = 0;
sources[n_sources].n_dead_probes = 0;
if (ip_addrs[i].family == IPADDR_INET4)
ip4++;
else if (ip_addrs[i].family == IPADDR_INET6)
ip6++;
n_sources++;
} else {
LOG(LOGS_WARN, LOGF_Acquire, "Ignoring duplicate source: %s",
UTI_IPToString(&ip_addrs[i]));
}
}
initialise_io((ip4 && ip6) ? IPADDR_UNSPEC : (ip4 ? IPADDR_INET4 : IPADDR_INET6));
/* Start sampling first source */
start_next_source();
return;
}
/* ================================================== */

View File

@@ -35,7 +35,7 @@ extern void ACQ_Initialise(void);
extern void ACQ_Finalise(void);
extern void ACQ_StartAcquisition(int n, IPAddr *ip_addrs, int init_slew_threshold,
extern void ACQ_StartAcquisition(int n, IPAddr *ip_addrs, double init_slew_threshold,
void (*after_hook)(void *), void *anything);
extern void ACQ_AccumulateSample(ACQ_Source acq_source, double offset, double root_distance);

View File

@@ -28,6 +28,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "addrfilt.h"
@@ -114,8 +116,6 @@ close_node(TableNode *node)
Free(node->extended);
node->extended = NULL;
}
return;
}
@@ -139,7 +139,6 @@ open_node(TableNode *node)
child_node->extended = NULL;
}
}
return;
}
/* ================================================== */
@@ -406,7 +405,6 @@ static void print_node(TableNode *node, uint32_t *addr, int ip_len, int shift, i
print_node(sub_node, new_addr, ip_len, shift - 4, subnet_bits + 4);
}
}
return;
}
@@ -421,7 +419,6 @@ static void print_table(ADF_AuthTable table)
memset(addr, 0, sizeof (addr));
printf("IPv6 table:\n");
print_node(&table->base6, addr, 4, 124, 0);
return;
}
/* ================================================== */

View File

@@ -24,6 +24,8 @@
Deal with broadcast server functions.
*/
#include "config.h"
#include "sysincl.h"
#include "memory.h"
@@ -47,7 +49,6 @@ static int max_destinations = 0;
void
BRD_Initialise(void)
{
return; /* Nothing to do */
}
/* ================================================== */
@@ -55,7 +56,6 @@ BRD_Initialise(void)
void
BRD_Finalise(void)
{
return; /* Nothing to do */
}
/* ================================================== */
@@ -71,7 +71,7 @@ timeout_handler(void *arbitrary)
int leap;
int are_we_synchronised, our_stratum;
NTP_Leap leap_status;
unsigned long our_ref_id;
uint32_t our_ref_id, ts_fuzz;
struct timeval our_ref_time;
double our_root_delay, our_root_dispersion;
struct timeval local_transmit;
@@ -89,7 +89,7 @@ timeout_handler(void *arbitrary)
if (are_we_synchronised) {
leap = (int) leap_status;
} else {
leap = 3;
leap = LEAP_Unsynchronised;
}
message.lvm = ((leap << 6) &0xc0) | ((version << 3) & 0x38) | (MODE_BROADCAST & 0x07);
@@ -99,20 +99,21 @@ timeout_handler(void *arbitrary)
/* If we're sending a client mode packet and we aren't synchronized yet,
we might have to set up artificial values for some of these parameters */
message.root_delay = double_to_int32(our_root_delay);
message.root_dispersion = double_to_int32(our_root_dispersion);
message.root_delay = UTI_DoubleToInt32(our_root_delay);
message.root_dispersion = UTI_DoubleToInt32(our_root_dispersion);
message.reference_id = htonl((NTP_int32) our_ref_id);
/* Now fill in timestamps */
UTI_TimevalToInt64(&our_ref_time, &message.reference_ts);
UTI_TimevalToInt64(&our_ref_time, &message.reference_ts, 0);
message.originate_ts.hi = 0UL;
message.originate_ts.lo = 0UL;
message.receive_ts.hi = 0UL;
message.receive_ts.lo = 0UL;
ts_fuzz = UTI_GetNTPTsFuzz(message.precision);
LCL_ReadCookedTime(&local_transmit, NULL);
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts);
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts, ts_fuzz);
NIO_SendNormalPacket(&message, &d->addr);
/* Requeue timeout. Don't care if interval drifts gradually, so just do it

84
candm.h
View File

@@ -31,6 +31,7 @@
#include "sysincl.h"
#include "addressing.h"
#include "hash.h"
/* This is the default port to use for CANDM, if no alternative is
defined */
@@ -297,22 +298,10 @@ typedef struct {
uint32_t bits_specd;
} REQ_SubnetsAccessed_Subnet;
#define MAX_SUBNETS_ACCESSED 8
typedef struct {
uint32_t n_subnets;
REQ_SubnetsAccessed_Subnet subnets[MAX_SUBNETS_ACCESSED];
} REQ_SubnetsAccessed;
/* This is based on the response size rather than the
request size */
#define MAX_CLIENT_ACCESSES 8
typedef struct {
uint32_t n_clients;
IPAddr client_ips[MAX_CLIENT_ACCESSES];
} REQ_ClientAccesses;
typedef struct {
uint32_t first_index;
uint32_t n_indices;
@@ -368,13 +357,27 @@ typedef struct {
and used also instead of integer microseconds, new commands: modify stratum,
modify polltarget, modify maxdelaydevratio, reselect, reselectdistance
Version 5 : auth data moved to the end of the packet to allow hashes with
different sizes, extended sources, tracking and activity reports, dropped
subnets accessed and client accesses
Version 6 : added padding to requests to prevent amplification attack,
changed maximum number of samples in manual list to 16
*/
#define PROTO_VERSION_NUMBER 4
#define PROTO_VERSION_NUMBER 6
/* The oldest protocol version that is compatible enough with
the current version to report a version mismatch */
#define PROTO_VERSION_MISMATCH_COMPAT 4
/* The oldest protocol versions that are compatible enough with the current
version to report a version mismatch for the server and the client */
#define PROTO_VERSION_MISMATCH_COMPAT_SERVER 5
#define PROTO_VERSION_MISMATCH_COMPAT_CLIENT 4
/* The first protocol version using padding in requests */
#define PROTO_VERSION_PADDING 6
/* The maximum length of padding in request packet, currently
defined by CLIENT_ACCESSES_BY_INDEX and MANUAL_LIST */
#define MAX_PADDING_LENGTH 396
/* ================================================== */
@@ -390,7 +393,6 @@ typedef struct {
uint32_t sequence; /* Client's sequence number */
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* Command token (to prevent replay attack) */
uint32_t auth[4]; /* MD5 authentication of the packet */
union {
REQ_Online online;
@@ -424,8 +426,6 @@ typedef struct {
REQ_RTCReport rtcreport;
REQ_TrimRTC trimrtc;
REQ_CycleLogs cyclelogs;
REQ_SubnetsAccessed subnets_accessed;
REQ_ClientAccesses client_accesses;
REQ_ClientAccessesByIndex client_accesses_by_index;
REQ_ManualList manual_list;
REQ_ManualDelete manual_delete;
@@ -435,6 +435,15 @@ typedef struct {
REQ_ReselectDistance reselect_distance;
} data; /* Command specific parameters */
/* The following fields only set the maximum size of the packet.
There are no holes between them and the actual data. */
/* Padding used to prevent traffic amplification */
uint8_t padding[MAX_PADDING_LENGTH];
/* Authentication data */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Request;
/* ================================================== */
@@ -472,6 +481,7 @@ typedef struct {
#define STT_BADSUBNET 7
#define STT_ACCESSALLOWED 8
#define STT_ACCESSDENIED 9
/* Deprecated */
#define STT_NOHOSTACCESS 10
#define STT_SOURCEALREADYKNOWN 11
#define STT_TOOMANYSOURCES 12
@@ -501,7 +511,10 @@ typedef struct {
#define RPY_SD_ST_FALSETICKER 2
#define RPY_SD_ST_JITTERY 3
#define RPY_SD_ST_CANDIDATE 4
#define RPY_SD_ST_OUTLYER 5
#define RPY_SD_ST_OUTLIER 5
#define RPY_SD_FLAG_NOSELECT 0x1
#define RPY_SD_FLAG_PREFER 0x2
typedef struct {
IPAddr ip_addr;
@@ -509,6 +522,8 @@ typedef struct {
uint16_t stratum;
uint16_t state;
uint16_t mode;
uint16_t flags;
uint16_t reachability;
uint32_t since_sample;
Float orig_latest_meas;
Float latest_meas;
@@ -519,14 +534,18 @@ typedef struct {
typedef struct {
uint32_t ref_id;
IPAddr ip_addr;
uint32_t stratum;
uint16_t stratum;
uint16_t leap_status;
Timeval ref_time;
Float current_correction;
Float last_offset;
Float rms_offset;
Float freq_ppm;
Float resid_freq_ppm;
Float skew_ppm;
Float root_delay;
Float root_dispersion;
Float last_update_interval;
int32_t EOR;
} RPY_Tracking;
@@ -567,11 +586,6 @@ typedef struct {
uint32_t bitmap[8];
} RPY_SubnetsAccessed_Subnet;
typedef struct {
uint32_t n_subnets;
RPY_SubnetsAccessed_Subnet subnets[MAX_SUBNETS_ACCESSED];
} RPY_SubnetsAccessed;
typedef struct {
IPAddr ip;
uint32_t client_hits;
@@ -583,19 +597,15 @@ typedef struct {
uint32_t last_cmd_hit_ago;
} RPY_ClientAccesses_Client;
typedef struct {
uint32_t n_clients;
RPY_ClientAccesses_Client clients[MAX_CLIENT_ACCESSES];
} RPY_ClientAccesses;
typedef struct {
uint32_t n_indices; /* how many indices there are in the server's table */
uint32_t next_index; /* the index 1 beyond those processed on this call */
uint32_t n_clients; /* the number of valid entries in the following array */
RPY_ClientAccesses_Client clients[MAX_CLIENT_ACCESSES];
int32_t EOR;
} RPY_ClientAccessesByIndex;
#define MAX_MANUAL_LIST_SAMPLES 32
#define MAX_MANUAL_LIST_SAMPLES 16
typedef struct {
Timeval when;
@@ -607,6 +617,7 @@ typedef struct {
typedef struct {
uint32_t n_samples;
RPY_ManualListSample samples[MAX_MANUAL_LIST_SAMPLES];
int32_t EOR;
} RPY_ManualList;
typedef struct {
@@ -614,6 +625,7 @@ typedef struct {
int32_t offline;
int32_t burst_online;
int32_t burst_offline;
int32_t unresolved;
int32_t EOR;
} RPY_Activity;
@@ -632,8 +644,6 @@ typedef struct {
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* New command token (only if command was successfully
authenticated) */
uint32_t auth[4]; /* MD5 authentication of the packet */
union {
RPY_Null null;
RPY_N_Sources n_sources;
@@ -642,13 +652,15 @@ typedef struct {
RPY_Tracking tracking;
RPY_Sourcestats sourcestats;
RPY_Rtc rtc;
RPY_SubnetsAccessed subnets_accessed;
RPY_ClientAccesses client_accesses;
RPY_ClientAccessesByIndex client_accesses_by_index;
RPY_ManualList manual_list;
RPY_Activity activity;
} data; /* Reply specific parameters */
/* authentication of the packet, there is no hole after the actual data
from the data union, this field only sets the maximum auth size */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Reply;
/* ================================================== */

View File

@@ -1,4 +1,4 @@
.TH CHRONY 1 "December 04, 2009" chrony "User's Manual"
.TH CHRONY 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
.SH NAME
chrony \- programs for keeping computer clocks accurate
@@ -21,7 +21,7 @@ to the Internet, and it can also act as an RFC1305-compatible NTP server.
.SH USAGE
\fIchronyc\fR is a command-line interface program which can be used to
monitor \fIchronyd\fR's performance and to change various operating
parateters whilst it is running.
parameters whilst it is running.
\fIchronyd\fR's main function is to obtain measurements of the true (UTC)
time from one of several sources, and correct the system clock
@@ -32,16 +32,16 @@ between measurements from the reference.
The reference time can be derived from either Network Time Protocol
(NTP) servers, reference clocks, or wristwatch-and-keyboard (via \fIchronyc\fR).
The main source of information about the Network Time Protocol is
\fIhttp://www.eecis.udel.edu/~ntp\fR.
\fIhttp://www.ntp.org\fR.
It is designed so that it can work on computers which only have
intermittent access to reference sources, for example computers which
use a dial-up account to access the Internet. Of course, it will work
on computers with permanent connections too.
use a dial-up account to access the Internet or laptops. Of course, it
will work well on computers with permanent connections too.
In addition, for Linux 2.0.x (for x >= 32) or 2.2 onwards, chronyd can monitor
the system's real time clock performance, so the system can maintain accurate
time even across reboots.
In addition, on Linux it can monitor the system's real time clock
performance, so the system can maintain accurate time even across
reboots.
Typical accuracies available between 2 machines are

View File

@@ -1,9 +1,9 @@
.TH chrony.conf 5 "December 04, 2009" chrony "Configuration Files"
.TH chrony.conf 5 "@MAN_DATE@" "chrony @VERSION@" "Configuration Files"
.SH NAME
chrony.conf \- chronyd configuration file
.SH SYNOPSIS
.B /etc/chrony.conf
.B @SYSCONFDIR@/chrony.conf
.SH DESCRIPTION
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
@@ -12,7 +12,7 @@ boot time.
Assuming that you have found some servers, you need to set up a
configuration file to run \fIchrony\fR. The (compiled-in) default location
for this file is \fB/etc/chrony.conf\fR. Assuming that your ntp servers
for this file is \fB@SYSCONFDIR@/chrony.conf\fR. Assuming that your ntp servers
are called `a.b.c' and `d.e.f', your \fBchrony.conf\fR file could contain
as a minimum
@@ -29,9 +29,9 @@ useful configuration file would look something like
server a.b.c
server d.e.f
server g.h.i
keyfile /etc/chrony.keys
keyfile @SYSCONFDIR@/chrony.keys
commandkey 1
driftfile /etc/chrony.drift
driftfile @CHRONYVARDIR@/drift
.SH "SEE ALSO"

View File

@@ -1,29 +0,0 @@
Begin3
Title: chrony
Version: 1.18
Entered-date: 01APR02
Description: A pair of programs for keeping computer clocks accurate.
chronyd is a background (daemon) program and chronyc is a
command-line interface to it. Time reference sources for
chronyd can be RFC1305 NTP servers, human (via keyboard and
chronyc), and the computer's real-time clock at boot time
(Linux only). chronyd can determine the rate at which the
computer gains or loses time and compensate for it whilst no
external reference is present. chronyd's use of NTP servers
can be switched on and off (through chronyc) to support
computers with dial-up/intermittent access to the
Internet. chronyd can also act as an RFC1305-compatible NTP
server.
Keywords: time NTP RFC1305 RTC adjtime
Author: rc@rc0.org.uk (Richard Curnow)
Maintained-by: rc@rc0.org.uk (Richard Curnow)
Primary-site: chrony.tuxfamily.org
295k chrony-1.18.tar.gz
2k chrony.lsm
Platforms: Linux 2.0/2.1/2.2/2.3/2.4 (x86, powerpc)
Solaris 2.5/6/7/8, SunOS 4.1.4. (Sparc)
BSDI/386.
NetBSD
Solaris 2.8 (x86)
Copying-policy: GPL
End

View File

@@ -1,38 +1,43 @@
%global chrony_version @@VERSION@@
%if 0%(echo %{chrony_version} | grep -q pre && echo 1)
%global prerelease %(echo %{chrony_version} | sed 's/.*-//')
%endif
Summary: An NTP client/server
Name: chrony
Version: @@VERSION@@
Release: 1
Source: chrony-%{version}.tar.gz
Copyright: GPL
Version: %(echo %{chrony_version} | sed 's/-.*//')
Release: %{!?prerelease:1}%{?prerelease:0.1.%{prerelease}}
Source: chrony-%{version}%{?prerelease:-%{prerelease}}.tar.gz
License: GPLv2
Group: Applications/Utilities
Packager: Richard P. Curnow <rc@rc0.org.uk>
BuildRoot: %{_tmppath}/%{name}-%{version}-root-%(id -u -n)
Requires: info
%description
A pair of programs for keeping computer clocks accurate. chronyd is a
background (daemon) program and chronyc is a command-line interface to it.
Time reference sources for chronyd can be RFC1305 NTP servers, human (via
keyboard and chronyc), and the computer's real-time clock at boot time (Linux
only). chronyd can determine the rate at which the computer gains or loses
time and compensate for it whilst no external reference is present. chronyd's
use of NTP servers can be switched on and off (through chronyc) to support
computers with dial-up/intermittent access to the Internet. chronyd can also
act as an RFC1305-compatible NTP server.
chrony is a client and server for the Network Time Protocol (NTP).
This program keeps your computer's clock accurate. It was specially
designed to support systems with intermittent Internet connections,
but it also works well in permanently connected environments. It can
also use hardware reference clocks, the system real-time clock, or
manual input as time references.
%prep
%setup
%setup -q -n %{name}-%{version}%{?prerelease:-%{prerelease}}
%build
./configure --prefix=%{_prefix} --mandir=%{_mandir}
make CC=gcc CFLAGS=-O2 prefix=%{_prefix}
make chrony.txt prefix=%{_prefix}
make chrony.info prefix=%{_prefix}
./configure \
--prefix=%{_prefix} \
--bindir=%{_bindir} \
--sbindir=%{_sbindir} \
--infodir=%{_infodir} \
--mandir=%{_mandir}
make
make chrony.txt
make chrony.info
%install
rm -rf $RPM_BUILD_ROOT
cd $RPM_BUILD_DIR/chrony-%{version}
make install DESTDIR=$RPM_BUILD_ROOT prefix=%{_prefix}
make install DESTDIR=$RPM_BUILD_ROOT
rm -rf $RPM_BUILD_ROOT%{_docdir}
mkdir -p $RPM_BUILD_ROOT%{_infodir}
cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
@@ -47,6 +52,6 @@ cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
%doc README
%doc chrony.txt
%doc COPYING
%doc examples/chrony.conf.example
%doc examples/chrony.conf.example*
%doc examples/chrony.keys.example

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,7 @@ struct timex {
#define ADJ_MAXERROR 0x0004 /* maximum time error */
#define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TIMECONST 0x0020 /* pll time constant */
#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
#define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */

View File

@@ -1,4 +1,4 @@
.TH CHRONYC 1 "May 02, 2011" chrony "User's Manual"
.TH CHRONYC 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
.SH NAME
chronyc \- command-line interface for chronyd
@@ -12,7 +12,7 @@ clocks.
\fBchronyc\fR is a command-line interface program which can be used to
monitor \fIchronyd\fR's performance and to change various operating
parateters whilst it is running.
parameters whilst it is running.
.SH USAGE
A detailed description of all commands supported by \fBchronyc\fR is available
@@ -42,14 +42,20 @@ resolve hostnames only to IPv6 addresses
allow multiple commands to be specified on the command line. Each argument
will be interpreted as a whole command.
.TP
\fB\-f\fR \fIconf-file\fR
This option can be used to specify an alternate location for the
configuration file (default \fI@SYSCONFDIR@/chrony.conf\fR). The configuration file is
needed for the \fB-a\fR option.
.TP
\fB\-a\fR
With this option chronyc will try to authenticate automatically on
start. It will read the configuration file, read the command key from the
keyfile and run the authhash and password commands.
.TP
\fIcommand\fR
specify command. If no command is given, chronyc will read commands
interactively.
.SH VERSION
1.25
.SH BUGS
To report bugs, please visit \fIhttp://chrony.tuxfamily.org\fR
@@ -67,4 +73,3 @@ Man Pages Project". Please see \fIhttp://www.netmeister.org/misc/m2p2/index.htm
for details.
The complete chrony documentation is supplied in texinfo format.

View File

@@ -1,4 +1,4 @@
.TH CHRONYD 8 "May 02, 2011" chrony "System Administration"
.TH CHRONYD 8 "@MAN_DATE@" "chrony @VERSION@" "System Administration"
.SH NAME
chronyd \- chrony background daemon
@@ -21,13 +21,13 @@ gains or loses time, and compensates for this.
.SH USAGE
\fBchronyd\fR is usually started at boot-time and requires superuser
priviliges.
privileges.
If \fBchronyd\fR has been installed to its default location
\fI/usr/local/sbin/chronyd\fR, starting it is simply a matter of entering the
\fI@SBINDIR@/chronyd\fR, starting it is simply a matter of entering the
command:
\fI/usr/local/sbin/chronyd\fR
\fI@SBINDIR@/chronyd\fR
Information messages and warnings will be logged to syslog.
@@ -56,7 +56,7 @@ to syslog.
.TP
\fB\-f\fR \fIconf-file\fR
This option can be used to specify an alternate location for the
configuration file (default \fI/etc/chrony.conf\fR).
configuration file (default \fI@SYSCONFDIR@/chrony.conf\fR).
.TP
.B \-r
This option will reload sample histories for each of the servers being used.
@@ -69,6 +69,12 @@ systems where the kernel can maintain clock compensation whilst not under
On systems where this is not the case, e.g. Solaris and SunOS the option
should not be used.
.TP
.B \-R
When this option is used, the \fIinitstepslew\fR directive and the
\fImakestep\fR directive used with a positive limit will be ignored. This
option is useful when restarting \fBchronyd\fR and can be used in conjuction
with the \fB-r\fR option.
.TP
.B \-s
This option will set the system clock from the computer's real-time
clock. This is analogous to supplying the \fI-s\fR flag to the
@@ -100,16 +106,13 @@ user. So far, it works only on Linux when compiled with capabilities support.
This option displays \fBchronyd\fR's version number to the terminal and exits
.TP
.B \-4
Resolve hostnames only to IPv4 addresses.
Resolve hostnames only to IPv4 addresses and create only IPv4 sockets.
.TP
.B \-6
Resolve hostnames only to IPv6 addresses.
Resolve hostnames only to IPv6 addresses and create only IPv6 sockets.
.SH FILES
\fI/etc/chrony.conf\fR
.SH VERSION
Version 1.25
\fI@SYSCONFDIR@/chrony.conf\fR
.SH BUGS
To report bugs, please visit \fIhttp://chrony.tuxfamily.org/\fR
@@ -122,8 +125,7 @@ from \fIhttp://go.to/chrony\fR
.BR chrony(1),
.BR chronyc(1),
.BR chrony.conf(5),
.BR clock(8),
.BR xntpd(8),
.BR hwclock(8),
.BR ntpd(8)
.SH AUTHOR

978
client.c

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "clientlog.h"
#include "conf.h"
@@ -172,7 +174,6 @@ CLG_Initialise(void)
void
CLG_Finalise(void)
{
return;
}
/* ================================================== */

374
cmdmon.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011
* Copyright (C) Miroslav Lichvar 2009-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,6 +25,8 @@
Command and monitoring module in the main program
*/
#include "config.h"
#include "sysincl.h"
#include "cmdmon.h"
@@ -32,7 +34,6 @@
#include "sched.h"
#include "util.h"
#include "logging.h"
#include "md5.h"
#include "keys.h"
#include "ntp_sources.h"
#include "ntp_core.h"
@@ -185,9 +186,6 @@ prepare_socket(int family)
int on_off = 1;
port_number = CNF_GetCommandPort();
if (port_number < 0) {
port_number = DEFAULT_CANDM_PORT;
}
sock_fd = socket(family, SOCK_DGRAM, 0);
if (sock_fd < 0) {
@@ -250,8 +248,10 @@ prepare_socket(int family)
}
if (bind(sock_fd, &my_addr.u, my_addr_len) < 0) {
LOG_FATAL(LOGF_CmdMon, "Could not bind %s command socket : %s",
LOG(LOGS_ERR, LOGF_CmdMon, "Could not bind %s command socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
close(sock_fd);
return -1;
}
/* Register handler for read events on the socket */
@@ -263,13 +263,27 @@ prepare_socket(int family)
/* ================================================== */
void
CAM_Initialise(void)
CAM_Initialise(int family)
{
int i;
assert(!initialised);
initialised = 1;
assert(sizeof (permissions) / sizeof (permissions[0]) == N_REQUEST_TYPES);
for (i = 0; i < N_REQUEST_TYPES; i++) {
CMD_Request r;
int command_length, padding_length;
r.version = PROTO_VERSION_NUMBER;
r.command = htons(i);
command_length = PKL_CommandLength(&r);
padding_length = PKL_CommandPaddingLength(&r);
assert(padding_length <= MAX_PADDING_LENGTH && padding_length <= command_length);
assert(command_length == 0 || command_length >= offsetof(CMD_Reply, data));
}
utoken = (unsigned long) time(NULL);
issued_tokens = returned_tokens = issue_pointer = 0;
@@ -279,9 +293,15 @@ CAM_Initialise(void)
free_replies = NULL;
kept_replies.next = NULL;
sock_fd4 = prepare_socket(AF_INET);
if (family == IPADDR_UNSPEC || family == IPADDR_INET4)
sock_fd4 = prepare_socket(AF_INET);
else
sock_fd4 = -1;
#ifdef HAVE_IPV6
sock_fd6 = prepare_socket(AF_INET6);
if (family == IPADDR_UNSPEC || family == IPADDR_INET6)
sock_fd6 = prepare_socket(AF_INET6);
else
sock_fd6 = -1;
#endif
if (sock_fd4 < 0
@@ -317,7 +337,6 @@ CAM_Finalise(void)
ADF_DestroyTable(access_auth_table);
initialised = 0;
return;
}
/* ================================================== */
@@ -326,57 +345,28 @@ CAM_Finalise(void)
rest of the packet */
static int
check_rx_packet_auth(CMD_Request *packet)
check_rx_packet_auth(CMD_Request *packet, int packet_len)
{
char *key;
int keylen;
int pkt_len;
MD5_CTX ctx;
int pkt_len, auth_len;
pkt_len = PKL_CommandLength(packet);
auth_len = packet_len - pkt_len;
KEY_CommandKey(&key, &keylen);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) key, keylen);
MD5Update(&ctx, (unsigned char *) packet, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Request, data)) {
MD5Update(&ctx, (unsigned char *) &(packet->data), pkt_len - offsetof(CMD_Request, data));
}
MD5Final(&ctx);
if (!memcmp((void *) &ctx.digest, (void *) &(packet->auth), 16)) {
return 1;
} else {
return 0;
}
return KEY_CheckAuth(KEY_GetCommandKey(), (unsigned char *)packet,
pkt_len, ((unsigned char *)packet) + pkt_len, auth_len);
}
/* ================================================== */
static void
static int
generate_tx_packet_auth(CMD_Reply *packet)
{
char *key;
int keylen;
MD5_CTX ctx;
int pkt_len;
pkt_len = PKL_ReplyLength(packet);
KEY_CommandKey(&key, &keylen);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) key, keylen);
MD5Update(&ctx, (unsigned char *) packet, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Reply, data)) {
MD5Update(&ctx, (unsigned char *) &(packet->data), pkt_len - offsetof(CMD_Reply, data));
}
MD5Final(&ctx);
memcpy(&(packet->auth), &ctx.digest, 16);
return KEY_GenerateAuth(KEY_GetCommandKey(), (unsigned char *)packet,
pkt_len, ((unsigned char *)packet) + pkt_len, sizeof (packet->auth));
}
/* ================================================== */
@@ -718,7 +708,7 @@ print_reply_packet(CMD_Reply *pkt)
/* ================================================== */
static void
transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to)
transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
{
int status;
int tx_message_length;
@@ -740,7 +730,7 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to)
assert(0);
}
tx_message_length = PKL_ReplyLength(msg);
tx_message_length = PKL_ReplyLength(msg) + auth_len;
status = sendto(sock_fd, (void *) msg, tx_message_length, 0,
&where_to->u, addrlen);
@@ -767,8 +757,6 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to)
LOG(LOGS_WARN, LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&ip), port);
}
return;
}
@@ -978,7 +966,7 @@ handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message)
if (MNL_AcceptTimestamp(&ts, &offset_cs, &dfreq_ppm, &new_afreq_ppm)) {
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_MANUAL_TIMESTAMP);
tx_message->data.manual_timestamp.centiseconds = htonl(offset_cs);
tx_message->data.manual_timestamp.centiseconds = htonl((int32_t)offset_cs);
tx_message->data.manual_timestamp.dfreq_ppm = UTI_FloatHostToNetwork(dfreq_ppm);
tx_message->data.manual_timestamp.new_afreq_ppm = UTI_FloatHostToNetwork(new_afreq_ppm);
} else {
@@ -1077,6 +1065,9 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
case RPT_CANDIDATE:
tx_message->data.source_data.state = htons(RPY_SD_ST_CANDIDATE);
break;
case RPT_OUTLIER:
tx_message->data.source_data.state = htons(RPY_SD_ST_OUTLIER);
break;
}
switch (report.mode) {
case RPT_NTP_CLIENT:
@@ -1089,6 +1080,18 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->data.source_data.mode = htons(RPY_SD_MD_REF);
break;
}
switch (report.sel_option) {
case RPT_NORMAL:
tx_message->data.source_data.flags = htons(0);
break;
case RPT_PREFER:
tx_message->data.source_data.flags = htons(RPY_SD_FLAG_PREFER);
break;
case RPT_NOSELECT:
tx_message->data.source_data.flags = htons(RPY_SD_FLAG_PREFER);
break;
}
tx_message->data.source_data.reachability = htons(report.reachability);
tx_message->data.source_data.since_sample = htonl(report.latest_meas_ago);
tx_message->data.source_data.orig_latest_meas = UTI_FloatHostToNetwork(report.orig_latest_meas);
tx_message->data.source_data.latest_meas = UTI_FloatHostToNetwork(report.latest_meas);
@@ -1381,7 +1384,7 @@ handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
usec = (long)(ntohl(rx_message->data.doffset.usec));
doffset = (double) sec + 1.0e-6 * (double) usec;
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset);
LCL_AccumulateOffset(doffset);
LCL_AccumulateOffset(doffset, 0.0);
tx_message->status = htons(STT_SUCCESS);
}
@@ -1397,14 +1400,18 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->reply = htons(RPY_TRACKING);
tx_message->data.tracking.ref_id = htonl(rpt.ref_id);
UTI_IPHostToNetwork(&rpt.ip_addr, &tx_message->data.tracking.ip_addr);
tx_message->data.tracking.stratum = htonl(rpt.stratum);
tx_message->data.tracking.stratum = htons(rpt.stratum);
tx_message->data.tracking.leap_status = htons(rpt.leap_status);
UTI_TimevalHostToNetwork(&rpt.ref_time, &tx_message->data.tracking.ref_time);
tx_message->data.tracking.current_correction = UTI_FloatHostToNetwork(rpt.current_correction);
tx_message->data.tracking.last_offset = UTI_FloatHostToNetwork(rpt.last_offset);
tx_message->data.tracking.rms_offset = UTI_FloatHostToNetwork(rpt.rms_offset);
tx_message->data.tracking.freq_ppm = UTI_FloatHostToNetwork(rpt.freq_ppm);
tx_message->data.tracking.resid_freq_ppm = UTI_FloatHostToNetwork(rpt.resid_freq_ppm);
tx_message->data.tracking.skew_ppm = UTI_FloatHostToNetwork(rpt.skew_ppm);
tx_message->data.tracking.root_delay = UTI_FloatHostToNetwork(rpt.root_delay);
tx_message->data.tracking.root_dispersion = UTI_FloatHostToNetwork(rpt.root_dispersion);
tx_message->data.tracking.last_update_interval = UTI_FloatHostToNetwork(rpt.last_update_interval);
}
/* ================================================== */
@@ -1458,7 +1465,6 @@ handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message)
} else {
tx_message->status = htons(STT_NORTC);
}
return;
}
/* ================================================== */
@@ -1473,7 +1479,6 @@ handle_trimrtc(CMD_Request *rx_message, CMD_Reply *tx_message)
} else {
tx_message->status = htons(STT_NORTC);
}
return;
}
/* ================================================== */
@@ -1484,110 +1489,6 @@ handle_cyclelogs(CMD_Request *rx_message, CMD_Reply *tx_message)
LOG_CycleLogFiles();
tx_message->status = htons(STT_SUCCESS);
return;
}
/* ================================================== */
#define FLIPL(X) ((X) = htonl(X))
static void
handle_subnets_accessed(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int i, j;
unsigned long ns, bits_specd;
IPAddr ip;
CLG_Status result;
ns = ntohl(rx_message->data.subnets_accessed.n_subnets);
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_SUBNETS_ACCESSED);
tx_message->data.subnets_accessed.n_subnets = htonl(ns);
for (i=0; i<ns; i++) {
UTI_IPNetworkToHost(&rx_message->data.subnets_accessed.subnets[i].ip, &ip);
bits_specd = ntohl(rx_message->data.subnets_accessed.subnets[i].bits_specd);
UTI_IPHostToNetwork(&ip, &tx_message->data.subnets_accessed.subnets[i].ip);
tx_message->data.subnets_accessed.subnets[i].bits_specd = htonl(bits_specd);
result = CLG_GetSubnetBitmap(&ip, bits_specd, tx_message->data.subnets_accessed.subnets[i].bitmap);
switch (result) {
case CLG_SUCCESS:
case CLG_EMPTYSUBNET:
/* Flip endianness of each 4 byte word. Don't care if subnet
is empty - just return an all-zero bitmap. */
for (j=0; j<8; j++) {
FLIPL(tx_message->data.subnets_accessed.subnets[i].bitmap[j]);
}
break;
case CLG_BADSUBNET:
tx_message->status = htons(STT_BADSUBNET);
return;
case CLG_INACTIVE:
tx_message->status = htons(STT_INACTIVE);
return;
default:
assert(0);
break;
}
}
return;
}
/* ================================================== */
static void
handle_client_accesses(CMD_Request *rx_message, CMD_Reply *tx_message)
{
CLG_Status result;
RPT_ClientAccess_Report report;
unsigned long nc;
IPAddr ip;
int i;
struct timeval now;
LCL_ReadCookedTime(&now, NULL);
nc = ntohl(rx_message->data.client_accesses.n_clients);
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_CLIENT_ACCESSES);
tx_message->data.client_accesses.n_clients = htonl(nc);
printf("%d %d\n", (int)sizeof(RPY_ClientAccesses_Client), (int)offsetof(CMD_Reply, data.client_accesses.clients));
for (i=0; i<nc; i++) {
UTI_IPNetworkToHost(&rx_message->data.client_accesses.client_ips[i], &ip);
UTI_IPHostToNetwork(&ip, &tx_message->data.client_accesses.clients[i].ip);
result = CLG_GetClientAccessReportByIP(&ip, &report, now.tv_sec);
switch (result) {
case CLG_SUCCESS:
tx_message->data.client_accesses.clients[i].client_hits = htonl(report.client_hits);
tx_message->data.client_accesses.clients[i].peer_hits = htonl(report.peer_hits);
tx_message->data.client_accesses.clients[i].cmd_hits_auth = htonl(report.cmd_hits_auth);
tx_message->data.client_accesses.clients[i].cmd_hits_normal = htonl(report.cmd_hits_normal);
tx_message->data.client_accesses.clients[i].cmd_hits_bad = htonl(report.cmd_hits_bad);
tx_message->data.client_accesses.clients[i].last_ntp_hit_ago = htonl(report.last_ntp_hit_ago);
tx_message->data.client_accesses.clients[i].last_cmd_hit_ago = htonl(report.last_cmd_hit_ago);
printf("%s %lu %lu %lu %lu %lu %lu %lu\n", UTI_IPToString(&ip), report.client_hits, report.peer_hits, report.cmd_hits_auth, report.cmd_hits_normal, report.cmd_hits_bad, report.last_ntp_hit_ago, report.last_cmd_hit_ago);
break;
case CLG_EMPTYSUBNET:
/* Signal back to the client that this single client address
was unknown */
ip.family = IPADDR_UNSPEC;
UTI_IPHostToNetwork(&ip, &tx_message->data.client_accesses.clients[i].ip);
break;
case CLG_INACTIVE:
tx_message->status = htons(STT_INACTIVE);
return;
default:
assert(0);
break;
}
}
}
/* ================================================== */
@@ -1692,7 +1593,6 @@ handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message)
{
LCL_MakeStep(0.0);
tx_message->status = htons(STT_SUCCESS);
return;
}
/* ================================================== */
@@ -1706,6 +1606,7 @@ handle_activity(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->data.activity.offline = htonl(report.offline);
tx_message->data.activity.burst_online = htonl(report.burst_online);
tx_message->data.activity.burst_offline = htonl(report.burst_offline);
tx_message->data.activity.unresolved = htonl(report.unresolved);
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_ACTIVITY);
}
@@ -1719,7 +1620,6 @@ handle_reselect_distance(CMD_Request *rx_message, CMD_Reply *tx_message)
dist = UTI_FloatNetworkToHost(rx_message->data.reselect_distance.distance);
SRC_SetReselectDistance(dist);
tx_message->status = htons(STT_SUCCESS);
return;
}
/* ================================================== */
@@ -1729,7 +1629,6 @@ handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
{
SRC_ReselectSource();
tx_message->status = htons(STT_SUCCESS);
return;
}
/* ================================================== */
@@ -1754,7 +1653,7 @@ read_from_cmd_socket(void *anything)
{
int status;
int read_length; /* Length of packet read */
int expected_length; /* Expected length of packet */
int expected_length; /* Expected length of packet without auth data */
unsigned long flags;
CMD_Request rx_message;
CMD_Reply tx_message, *prev_tx_message;
@@ -1764,7 +1663,8 @@ read_from_cmd_socket(void *anything)
socklen_t from_length;
IPAddr remote_ip;
unsigned short remote_port;
int md5_ok;
int auth_length;
int auth_ok;
int utoken_ok, token_ok;
int issue_token;
int valid_ts;
@@ -1794,29 +1694,10 @@ read_from_cmd_socket(void *anything)
}
read_length = status;
expected_length = PKL_CommandLength(&rx_message);
rx_command = ntohs(rx_message.command);
LCL_ReadRawTime(&now);
LCL_CookTime(&now, &cooked_now, NULL);
tx_message.version = PROTO_VERSION_NUMBER;
tx_message.pkt_type = PKT_TYPE_CMD_REPLY;
tx_message.res1 = 0;
tx_message.res2 = 0;
tx_message.command = rx_message.command;
tx_message.sequence = rx_message.sequence;
tx_message.reply = htons(RPY_NULL);
tx_message.number = htons(1);
tx_message.total = htons(1);
tx_message.pad1 = 0;
tx_message.utoken = htonl(utoken);
/* Set this to a default (invalid) value. This protects against the
token field being set to an arbitrary value if we reject the
message, e.g. due to the host failing the access check. */
tx_message.token = htonl(0xffffffffUL);
memset(&tx_message.auth, 0, sizeof(tx_message.auth));
switch (where_from.u.sa_family) {
case AF_INET:
remote_ip.family = IPADDR_INET4;
@@ -1841,31 +1722,63 @@ read_from_cmd_socket(void *anything)
assert(0);
}
allowed = ADF_IsAllowed(access_auth_table, &remote_ip) || localhost;
if (!(localhost || ADF_IsAllowed(access_auth_table, &remote_ip))) {
/* 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! */
return;
}
if (read_length < offsetof(CMD_Request, data) ||
/* Message size sanity check */
if (read_length >= offsetof(CMD_Request, data)) {
expected_length = PKL_CommandLength(&rx_message);
} else {
expected_length = 0;
}
if (expected_length < offsetof(CMD_Request, data) ||
read_length < offsetof(CMD_Reply, data) ||
rx_message.pkt_type != PKT_TYPE_CMD_REQUEST ||
rx_message.res1 != 0 ||
rx_message.res2 != 0) {
/* 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;
}
rx_command = ntohs(rx_message.command);
tx_message.version = PROTO_VERSION_NUMBER;
tx_message.pkt_type = PKT_TYPE_CMD_REPLY;
tx_message.res1 = 0;
tx_message.res2 = 0;
tx_message.command = rx_message.command;
tx_message.sequence = rx_message.sequence;
tx_message.reply = htons(RPY_NULL);
tx_message.number = htons(1);
tx_message.total = htons(1);
tx_message.pad1 = 0;
tx_message.utoken = htonl(utoken);
/* Set this to a default (invalid) value. This protects against the
token field being set to an arbitrary value if we reject the
message, e.g. due to the host failing the access check. */
tx_message.token = htonl(0xffffffffUL);
memset(&tx_message.auth, 0, sizeof(tx_message.auth));
if (rx_message.version != PROTO_VERSION_NUMBER) {
tx_message.status = htons(STT_NOHOSTACCESS);
if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Read command 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);
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT) {
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT_SERVER) {
tx_message.status = htons(STT_BADPKTVERSION);
transmit_reply(&tx_message, &where_from);
transmit_reply(&tx_message, &where_from, 0);
}
return;
}
@@ -1874,41 +1787,23 @@ read_from_cmd_socket(void *anything)
if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Read command packet with invalid command %d from %s:%hu", rx_command, 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_INVALID);
transmit_reply(&tx_message, &where_from);
transmit_reply(&tx_message, &where_from, 0);
return;
}
if (read_length != expected_length) {
if (read_length < expected_length) {
if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Read incorrectly sized command 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);
transmit_reply(&tx_message, &where_from);
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);
transmit_reply(&tx_message, &where_from, 0);
return;
}
@@ -1918,18 +1813,18 @@ read_from_cmd_socket(void *anything)
clients will set their utokens to 0 to save us wasting our time
if the packet is unauthenticatable. */
if (rx_message.utoken != 0) {
md5_ok = check_rx_packet_auth(&rx_message);
auth_ok = check_rx_packet_auth(&rx_message, read_length);
} else {
md5_ok = 0;
auth_ok = 0;
}
/* All this malarky is to protect the system against various forms
of attack.
Simple packet forgeries are blocked by requiring the packet to
authenticate properly with MD5. (The assumption is that the
command key is in a read-only keys file read by the daemon, and
is known only to administrators.)
authenticate properly with MD5 or other crypto hash. (The
assumption is that the command key is in a read-only keys file
read by the daemon, and is known only to administrators.)
Replay attacks are prevented by 2 fields in the packet. The
'token' field is where the client plays back to us a token that
@@ -1971,13 +1866,13 @@ read_from_cmd_socket(void *anything)
rx_message_seq = ntohl(rx_message.sequence);
rx_attempt = ntohs(rx_message.attempt);
if (md5_ok && utoken_ok) {
if (auth_ok && utoken_ok) {
token_ok = check_token(rx_message_token);
} else {
token_ok = 0;
}
if (md5_ok && utoken_ok && !token_ok) {
if (auth_ok && utoken_ok && !token_ok) {
/* This might be a resent message, due to the client not getting
our reply to the first attempt. See if we can find the message. */
prev_tx_message = lookup_reply(rx_message_token, rx_message_seq, rx_attempt);
@@ -1995,14 +1890,14 @@ read_from_cmd_socket(void *anything)
}
if (md5_ok && utoken_ok && token_ok) {
if (auth_ok && utoken_ok && token_ok) {
/* See whether we can discard the previous reply from storage */
token_acknowledged(rx_message_token, &now);
}
valid_ts = 0;
if (md5_ok) {
if (auth_ok) {
struct timeval ts;
UTI_TimevalNetworkToHost(&rx_message.data.logon.ts, &ts);
@@ -2017,7 +1912,7 @@ read_from_cmd_socket(void *anything)
issue_token = 0;
}
authenticated = md5_ok & utoken_ok & token_ok;
authenticated = auth_ok & utoken_ok & token_ok;
if (authenticated) {
CLG_LogCommandAccess(&remote_ip, CLG_CMD_AUTH, cooked_now.tv_sec);
@@ -2117,15 +2012,15 @@ read_from_cmd_socket(void *anything)
/* If the log-on fails, record the reason why */
if (!issue_token && !LOG_RateLimited()) {
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 (auth_ok=%d valid_ts=%d)",
UTI_IPToString(&remote_ip),
remote_port,
md5_ok, valid_ts);
auth_ok, valid_ts);
}
if (issue_token == 1) {
tx_message.status = htons(STT_SUCCESS);
} else if (!md5_ok) {
} else if (!auth_ok) {
tx_message.status = htons(STT_UNAUTH);
} else if (!valid_ts) {
tx_message.status = htons(STT_INVALIDTS);
@@ -2243,14 +2138,6 @@ read_from_cmd_socket(void *anything)
handle_cyclelogs(&rx_message, &tx_message);
break;
case REQ_SUBNETS_ACCESSED:
handle_subnets_accessed(&rx_message, &tx_message);
break;
case REQ_CLIENT_ACCESSES:
handle_client_accesses(&rx_message, &tx_message);
break;
case REQ_CLIENT_ACCESSES_BY_INDEX:
handle_client_accesses_by_index(&rx_message, &tx_message);
break;
@@ -2296,8 +2183,10 @@ read_from_cmd_socket(void *anything)
}
}
if (md5_ok) {
generate_tx_packet_auth(&tx_message);
if (auth_ok) {
auth_length = generate_tx_packet_auth(&tx_message);
} else {
auth_length = 0;
}
if (token_ok) {
@@ -2316,16 +2205,13 @@ read_from_cmd_socket(void *anything)
static int do_it=1;
if (do_it) {
transmit_reply(&tx_message, &where_from);
transmit_reply(&tx_message, &where_from, auth_length);
}
#if 0
do_it = ((do_it + 1) % 3);
#endif
}
return;
}
/* ================================================== */

View File

@@ -29,7 +29,7 @@
#include "addressing.h"
extern void CAM_Initialise(void);
extern void CAM_Initialise(int family);
extern void CAM_Finalise(void);

View File

@@ -3,6 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2013
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -26,24 +27,23 @@
*/
#include "config.h"
#include "sysincl.h"
#include "cmdparse.h"
#include "memory.h"
#include "nameserv.h"
#define MAXLEN 2047
#define SMAXLEN "2047"
#include "util.h"
/* ================================================== */
CPS_Status
CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
{
char *hostname, *cmd;
int ok, n, done;
char cmd[MAXLEN+1], hostname[MAXLEN+1];
CPS_Status result;
DNS_Status s;
src->port = SRC_DEFAULT_PORT;
src->params.minpoll = SRC_DEFAULT_MINPOLL;
@@ -62,33 +62,22 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
result = CPS_Success;
ok = 0;
if (sscanf(line, "%" SMAXLEN "s%n", hostname, &n) == 1) {
s = DNS_Name2IPAddress(hostname, &src->ip_addr);
if (s == DNS_Success) {
ok = 1;
src->name = NULL;
} else if (s == DNS_TryAgain) {
ok = 1;
src->ip_addr.family = IPADDR_UNSPEC;
}
}
hostname = line;
line = CPS_SplitWord(line);
if (!ok) {
if (!*hostname) {
result = CPS_BadHost;
ok = 0;
} else {
line += n;
/* Parse subfields */
ok = 1;
done = 0;
do {
if (sscanf(line, "%" SMAXLEN "s%n", cmd, &n) == 1) {
line += n;
if (!strncasecmp(cmd, "port", 4)) {
cmd = line;
line = CPS_SplitWord(line);
if (*cmd) {
if (!strcasecmp(cmd, "port")) {
if (sscanf(line, "%hu%n", &src->port, &n) != 1) {
result = CPS_BadPort;
ok = 0;
@@ -96,7 +85,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "minpoll", 7)) {
} else if (!strcasecmp(cmd, "minpoll")) {
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1) {
result = CPS_BadMinpoll;
ok = 0;
@@ -104,7 +93,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "maxpoll", 7)) {
} else if (!strcasecmp(cmd, "maxpoll")) {
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1) {
result = CPS_BadMaxpoll;
ok = 0;
@@ -112,7 +101,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "presend", 7)) {
} else if (!strcasecmp(cmd, "presend")) {
if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1) {
result = CPS_BadPresend;
ok = 0;
@@ -120,7 +109,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "maxdelaydevratio", 16)) {
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1) {
result = CPS_BadMaxdelaydevratio;
ok = 0;
@@ -128,8 +117,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
/* This MUST come before the following one ! */
} else if (!strncasecmp(cmd, "maxdelayratio", 13)) {
} else if (!strcasecmp(cmd, "maxdelayratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) {
result = CPS_BadMaxdelayratio;
ok = 0;
@@ -137,7 +125,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "maxdelay", 8)) {
} else if (!strcasecmp(cmd, "maxdelay")) {
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1) {
result = CPS_BadMaxdelay;
ok = 0;
@@ -145,7 +133,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "key", 3)) {
} else if (!strcasecmp(cmd, "key")) {
if (sscanf(line, "%lu%n", &src->params.authkey, &n) != 1) {
result = CPS_BadKey;
ok = 0;
@@ -153,16 +141,16 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} else {
line += n;
}
} else if (!strncasecmp(cmd, "offline", 7)) {
} else if (!strcasecmp(cmd, "offline")) {
src->params.online = 0;
} else if (!strncasecmp(cmd, "auto_offline", 12)) {
} else if (!strcasecmp(cmd, "auto_offline")) {
src->params.auto_offline = 1;
} else if (!strncasecmp(cmd, "iburst", 6)) {
} else if (!strcasecmp(cmd, "iburst")) {
src->params.iburst = 1;
} else if (!strncasecmp(cmd, "minstratum", 10)) {
} else if (!strcasecmp(cmd, "minstratum")) {
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1) {
result = CPS_BadMinstratum;
ok = 0;
@@ -171,7 +159,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
line += n;
}
} else if (!strncasecmp(cmd, "polltarget", 10)) {
} else if (!strcasecmp(cmd, "polltarget")) {
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1) {
result = CPS_BadPolltarget;
ok = 0;
@@ -180,10 +168,10 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
line += n;
}
} else if (!strncasecmp(cmd, "noselect", 8)) {
} else if (!strcasecmp(cmd, "noselect")) {
src->params.sel_option = SRC_SelectNoselect;
} else if (!strncasecmp(cmd, "prefer", 6)) {
} else if (!strcasecmp(cmd, "prefer")) {
src->params.sel_option = SRC_SelectPrefer;
} else {
@@ -197,11 +185,8 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} while (!done);
}
if (ok && src->ip_addr.family == IPADDR_UNSPEC) {
n = strlen(hostname);
src->name = MallocArray(char, n + 1);
strncpy(src->name, hostname, n);
src->name[n] = '\0';
if (ok) {
src->name = strdup(hostname);
}
return result;
@@ -210,3 +195,87 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
/* ================================================== */
void
CPS_NormalizeLine(char *line)
{
char *p, *q;
int space = 1, first = 1;
/* Remove white-space at beginning and replace white-spaces with space char */
for (p = q = line; *p; p++) {
if (isspace(*p)) {
if (!space)
*q++ = ' ';
space = 1;
continue;
}
/* Discard comment lines */
if (first && strchr("!;#%", *p))
break;
*q++ = *p;
space = first = 0;
}
/* Strip trailing space */
if (q > line && q[-1] == ' ')
q--;
*q = '\0';
}
/* ================================================== */
char *
CPS_SplitWord(char *line)
{
char *p = line, *q = line;
/* Skip white-space before the word */
while (*q && isspace(*q))
q++;
/* Move the word to the beginning */
while (*q && !isspace(*q))
*p++ = *q++;
/* Find the next word */
while (*q && isspace(*q))
q++;
*p = '\0';
/* Return pointer to the next word or NUL */
return q;
}
/* ================================================== */
int
CPS_ParseKey(char *line, unsigned long *id, const char **hash, char **key)
{
char *s1, *s2, *s3, *s4;
s1 = line;
s2 = CPS_SplitWord(s1);
s3 = CPS_SplitWord(s2);
s4 = CPS_SplitWord(s3);
/* Require two or three words */
if (!*s2 || *s4)
return 0;
if (sscanf(s1, "%lu", id) != 1)
return 0;
if (*s3) {
*hash = s2;
*key = s3;
} else {
*hash = "MD5";
*key = s2;
}
return 1;
}

View File

@@ -47,15 +47,21 @@ typedef enum {
} CPS_Status;
typedef struct {
IPAddr ip_addr;
char *name;
unsigned short port;
SourceParameters params;
} CPS_NTP_Source;
/* Parse a command to add an NTP server or peer */
extern CPS_Status CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src);
extern CPS_Status CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
/* Remove extra white-space and comments */
extern void CPS_NormalizeLine(char *line);
/* Terminate first word and return pointer to the next word */
extern char *CPS_SplitWord(char *line);
/* Parse a key from keyfile */
extern int CPS_ParseKey(char *line, unsigned long *id, const char **hash, char **key);
#endif /* GOT_CMDPARSE_H */

1069
conf.c

File diff suppressed because it is too large Load Diff

12
conf.h
View File

@@ -29,6 +29,8 @@
#include "addressing.h"
extern void CNF_SetRestarted(int);
extern char *CNF_GetRtcDevice(void);
extern void CNF_ReadFile(const char *filename);
@@ -54,12 +56,14 @@ extern int CNF_GetLogTempComp(void);
extern char *CNF_GetKeysFile(void);
extern char *CNF_GetRtcFile(void);
extern unsigned long CNF_GetCommandKey(void);
extern int CNF_GetGenerateCommandKey(void);
extern int CNF_GetDumpOnExit(void);
extern int CNF_GetManualEnabled(void);
extern int CNF_GetCommandPort(void);
extern int CNF_GetRTCOnUTC(void);
extern int CNF_GetRTCSync(void);
extern void CNF_GetMakeStep(int *limit, double *threshold);
extern void CNF_GetMaxChange(int *delay, int *ignore, double *offset);
extern void CNF_GetLogChange(int *enabled, double *threshold);
extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user);
extern int CNF_GetNoClientLog(void);
@@ -68,15 +72,18 @@ extern void CNF_GetFallbackDrifts(int *min, int *max);
extern void CNF_GetBindAddress(int family, IPAddr *addr);
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
extern char *CNF_GetPidFile(void);
extern char *CNF_GetLeapSecTimezone(void);
extern void CNF_GetLinuxHz(int *set, int *hz);
extern void CNF_GetLinuxFreqScale(int *set, double *freq_scale);
/* Value returned in ppm, as read from file */
extern double CNF_GetMaxUpdateSkew(void);
extern double CNF_GetMaxClockError(void);
extern double CNF_GetCorrectionTimeRatio(void);
extern double CNF_GetReselectDistance(void);
extern double CNF_GetStratumWeight(void);
extern double CNF_GetCombineLimit(void);
extern int CNF_AllowLocalReference(int *stratum);
@@ -87,4 +94,9 @@ extern int CNF_GetLockMemory(void);
extern void CNF_GetTempComp(char **file, double *interval, double *T0, double *k0, double *k1, double *k2);
extern char *CNF_GetUser(void);
extern int CNF_GetMaxSamples(void);
extern int CNF_GetMinSamples(void);
#endif /* GOT_CONF_H */

252
configure vendored
View File

@@ -4,10 +4,12 @@
# chronyd/chronyc - Programs for keeping computer clocks accurate.
#
# Copyright (C) Richard P. Curnow 1997-2003
# Copyright (C) Miroslav Lichvar 2009
# Copyright (C) Miroslav Lichvar 2009, 2012
#
# =======================================================================
rm -f config.h config.log
# This configure script determines the operating system type and version
if [ "x${CC}" = "x" ]; then
@@ -25,9 +27,7 @@ fi
MYCPPFLAGS="${CPPFLAGS}"
if [ "x${MYCC}" = "xgcc" ]; then
CCWARNFLAGS="-Wmissing-prototypes -Wall"
else
CCWARNFLAGS=""
MYCFLAGS="${MYCFLAGS} -Wmissing-prototypes -Wall"
fi
MYLDFLAGS="${LDFLAGS}"
@@ -43,7 +43,7 @@ test_code () {
ldflags=$4
code=$5
printf "Checking for $name : "
echo -n "Checking for $name : "
(
for h in $headers; do
@@ -54,23 +54,30 @@ test_code () {
echo "return 0; }"
) > docheck.c
$MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o docheck docheck.c $ldflags $MYLDFLAGS >/dev/null 2>&1
echo "docheck.c:" >> config.log
cat docheck.c >> config.log
echo $MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o docheck docheck.c $ldflags \
$MYLDFLAGS >> config.log
$MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o docheck docheck.c $ldflags \
$MYLDFLAGS >> config.log 2>&1
if [ $? -eq 0 ]
then
printf "Yes\n"
echo "Yes"
result=0
else
printf "No\n"
echo "No"
result=1
fi
rm -f docheck.c docheck
echo >> config.log
return $result
}
#}}}
#{{{ usage
usage () {
cat <<EOF;
\`configure' configures tdl to adapt to many kinds of systems.
cat <<EOF
\`configure' configures this package to adapt to many kinds of systems.
Usage: ./configure [OPTION]...
@@ -98,11 +105,15 @@ For better control, use the options below.
--readline-inc-dir=DIR Specify where readline include directory is
--readline-lib-dir=DIR Specify where readline lib directory is
--with-ncurses-library=DIR Specify where ncurses lib directory is
--without-nss Don't use NSS even if it is available
--without-tomcrypt Don't use libtomcrypt even if it is available
--disable-ipv6 Disable IPv6 support
--disable-pps Disable PPS API support
--disable-rtc Don't include RTC even on Linux
--disable-linuxcaps Disable Linux capabilities support
--enable-forcednsretry Force retry on DNS failure
--disable-forcednsretry Don't retry on permanent DNS error
--with-sendmail=PATH Path to sendmail binary [/usr/lib/sendmail]
--enable-trace Enable tracing
Fine tuning of the installation directories:
--sysconfdir=DIR chrony.conf location [/etc]
@@ -112,6 +123,8 @@ Fine tuning of the installation directories:
--infodir=DIR info documentation [DATAROOTDIR/info]
--mandir=DIR man documentation [DATAROOTDIR/man]
--docdir=DIR documentation root [DATAROOTDIR/doc/chrony]
--localstatedir=DIR modifiable single-machine data [/var]
--chronyvardir=DIR location for chrony data [LOCALSTATEDIR/lib/chrony]
Overriding system detection when cross-compiling:
--host-system=OS Specify system name (uname -s)
@@ -133,6 +146,15 @@ EOF
}
#}}}
#{{{
add_def () {
if [ "x$2" = "x" ]; then
echo "#define $1 1" >> config.h
else
echo "#define $1 $2" >> config.h
fi
}
#}}}
# ======================================================================
@@ -152,6 +174,8 @@ SYSDEFS=""
feat_readline=1
try_readline=1
try_editline=1
try_nss=1
try_tomcrypt=1
feat_rtc=1
try_rtc=0
feat_linuxcaps=1
@@ -163,13 +187,14 @@ feat_ipv6=1
feat_pps=1
try_setsched=0
try_lockmem=0
feat_forcednsretry=0
feat_forcednsretry=1
mail_program="/usr/lib/sendmail"
for option
do
case "$option" in
--trace )
EXTRA_DEFS="-DTRACEON"
--enable-trace )
add_def TRACEON
;;
--disable-readline )
feat_readline=0
@@ -216,6 +241,12 @@ do
--docdir=* )
SETDOCDIR=`echo $option | sed -e 's/^.*=//;'`
;;
--localstatedir=* )
SETLOCALSTATEDIR=`echo $option | sed -e 's/^.*=//;'`
;;
--chronyvardir=* )
SETCHRONYVARDIR=`echo $option | sed -e 's/^.*=//;'`
;;
--disable-rtc)
feat_rtc=0
;;
@@ -228,8 +259,17 @@ do
--disable-linuxcaps)
feat_linuxcaps=0
;;
--enable-forcednsretry)
feat_forcednsretry=1
--disable-forcednsretry)
feat_forcednsretry=0
;;
--with-sendmail=* )
mail_program=`echo $option | sed -e 's/^.*=//;'`
;;
--without-nss )
try_nss=0
;;
--without-tomcrypt )
try_tomcrypt=0
;;
--host-system=* )
OPERATINGSYSTEM=`echo $option | sed -e 's/^.*=//;'`
@@ -257,19 +297,15 @@ case $SYSTEM in
4.* )
EXTRA_OBJECTS="sys_sunos.o strerror.o"
EXTRA_LIBS="-lkvm"
SYSDEFS="-DSUNOS"
add_def SUNOS
echo "Configuring for SunOS (" $SYSTEM "version" $VERSION ")"
;;
5.* )
EXTRA_OBJECTS="sys_solaris.o"
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
EXTRA_CLI_LIBS="-lsocket -lnsl"
SYSDEFS="-DSOLARIS"
add_def SOLARIS
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
if [ $VERSION = "5.3" ]; then
SYSDEFS="$SYSDEFS -DHAS_NO_BZERO"
echo "Using memset() instead of bzero()"
fi
;;
esac
;;
@@ -279,12 +315,12 @@ case $SYSTEM in
try_rtc=1
try_setsched=1
try_lockmem=1
SYSDEFS="-DLINUX"
add_def LINUX
echo "Configuring for " $SYSTEM
if [ "${MACHINE}" = "alpha" ]; then
echo "Enabling -mieee"
# FIXME: Should really test for GCC
SYSDEFS="$SYSDEFS -mieee -DALPHA"
MYCFLAGS="$MYCFLAGS -mieee"
fi
;;
@@ -293,7 +329,7 @@ case $SYSTEM in
# be supported with the SunOS 4.x driver files.
EXTRA_OBJECTS="sys_sunos.o strerror.o"
EXTRA_LIBS="-lkvm"
SYSDEFS="-DSUNOS"
add_def SUNOS
echo "Configuring for $SYSTEM (using SunOS driver)"
;;
NetBSD-* )
@@ -308,13 +344,13 @@ case $SYSTEM in
EXTRA_OBJECTS="sys_solaris.o"
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
EXTRA_CLI_LIBS="-lsocket -lnsl"
SYSDEFS="-DSOLARIS"
add_def SOLARIS
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
;;
CYGWIN32_NT-i[3456]86 )
EXTRA_OBJECTS="sys_winnt.o"
EXTRA_LIBS=""
SYSDEFS="-DWINNT"
add_def WINNT
echo "Configuring for Windows NT (Cygwin32)"
;;
* )
@@ -330,17 +366,17 @@ else
if test_code 'math in -lm' 'math.h' '' '-lm' "$MATHCODE"; then
LIBS="-lm"
else
printf "Can't compile/link a program which uses sqrt(), log(), pow(), bailing out\n"
echo "Can't compile/link a program which uses sqrt(), log(), pow(), bailing out"
exit 1
fi
fi
if test_code '<stdint.h>' 'stdint.h' '' '' ''; then
SYSDEFS="${SYSDEFS} -DHAS_STDINT_H"
add_def HAS_STDINT_H
fi
if test_code '<inttypes.h>' 'inttypes.h' '' '' ''; then
SYSDEFS="${SYSDEFS} -DHAS_INTTYPES_H"
add_def HAS_INTTYPES_H
fi
if [ $feat_ipv6 = "1" ] && \
@@ -350,17 +386,42 @@ if [ $feat_ipv6 = "1" ] && \
n.sin6_addr = in6addr_any;
return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));'
then
SYSDEFS="${SYSDEFS} -DHAVE_IPV6"
add_def HAVE_IPV6
if test_code 'in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
return sizeof(struct in6_pktinfo);'
then
add_def HAVE_IN6_PKTINFO
else
if test_code 'in6_pktinfo with _GNU_SOURCE' 'sys/socket.h netinet/in.h' \
'-D_GNU_SOURCE' '' 'return sizeof(struct in6_pktinfo);'
then
add_def _GNU_SOURCE
add_def HAVE_IN6_PKTINFO
fi
fi
fi
if [ $feat_pps = "1" ] && \
test_code 'PPS API' 'string.h timepps.h' '' '' '
timepps_h=""
if [ $feat_pps = "1" ]; then
if test_code '<sys/timepps.h>' 'sys/timepps.h' '' '' ''; then
timepps_h="sys/timepps.h"
add_def HAVE_SYS_TIMEPPS_H
else
if test_code '<timepps.h>' 'timepps.h' '' '' ''; then
timepps_h="timepps.h"
add_def HAVE_TIMEPPS_H
fi
fi
fi
if [ "x$timepps_h" != "x" ] && \
test_code 'PPSAPI' "string.h $timepps_h" '' '' '
pps_handle_t h;
pps_info_t i;
struct timespec ts;
return time_pps_fetch(h, PPS_TSFMT_TSPEC, &i, &ts);'
then
SYSDEFS="${SYSDEFS} -DHAVE_PPSAPI"
add_def HAVE_PPSAPI
fi
if [ $feat_linuxcaps = "1" ] && [ $try_linuxcaps = "1" ] && \
@@ -370,7 +431,7 @@ if [ $feat_linuxcaps = "1" ] && [ $try_linuxcaps = "1" ] && \
'' '-lcap' \
'prctl(PR_SET_KEEPCAPS, 1);cap_set_proc(cap_from_text("cap_sys_time=ep"));'
then
EXTRA_DEFS="${EXTRA_DEFS} -DFEAT_LINUXCAPS=1"
add_def FEAT_LINUXCAPS
EXTRA_LIBS="-lcap"
fi
@@ -379,7 +440,7 @@ if [ $feat_rtc = "1" ] && [ $try_rtc = "1" ] && \
'ioctl(1, RTC_UIE_ON&RTC_UIE_OFF&RTC_RD_TIME&RTC_SET_TIME, 0&RTC_UF);'
then
EXTRA_OBJECTS="$EXTRA_OBJECTS rtc_linux.o"
EXTRA_DEFS="$EXTRA_DEFS -DFEAT_RTC=1"
add_def FEAT_RTC
fi
if [ $try_setsched = "1" ] && \
@@ -390,7 +451,7 @@ if [ $try_setsched = "1" ] && \
sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &sched);'
then
SYSDEFS="${SYSDEFS} -DHAVE_SCHED_SETSCHEDULER"
add_def HAVE_SCHED_SETSCHEDULER
fi
if [ $try_lockmem = "1" ] && \
@@ -401,12 +462,12 @@ if [ $try_lockmem = "1" ] && \
setrlimit(RLIMIT_MEMLOCK, &rlim);
mlockall(MCL_CURRENT|MCL_FUTURE);'
then
SYSDEFS="${SYSDEFS} -DHAVE_MLOCKALL"
add_def HAVE_MLOCKALL
fi
if [ $feat_forcednsretry = "1" ]
then
EXTRA_DEFS="$EXTRA_DEFS -DFORCE_DNSRETRY=1"
add_def FORCE_DNSRETRY
fi
READLINE_COMPILE=""
@@ -417,22 +478,66 @@ if [ $feat_readline = "1" ]; then
"$readline_inc" "$readline_lib -ledit" \
'add_history(readline("prompt"));'
then
READLINE_COMPILE="-DFEAT_READLINE=1 -DUSE_EDITLINE=1 $readline_inc"
add_def FEAT_READLINE
add_def USE_EDITLINE
READLINE_COMPILE="$readline_inc"
READLINE_LINK="$readline_lib -ledit"
fi
fi
if [ "x$READLINE_LINK" = "x" ] && [ $try_readline = "1" ]; then
if test_code readline 'stdio.h readline/readline.h readline/history.h' \
"$readline_inc" "$readline_lib $ncurses_lib -lreadline" \
'add_history(readline("prompt"));'
then
add_def FEAT_READLINE
READLINE_COMPILE="$readline_inc"
READLINE_LINK="$readline_lib $ncurses_lib -lreadline"
fi
fi
if [ "x$READLINE_LINK" = "x" ] && [ $try_readline = "1" ]; then
if test_code 'readline with -lncurses' \
'stdio.h readline/readline.h readline/history.h' \
"$readline_inc" "$readline_lib $ncurses_lib -lreadline -lncurses" \
'add_history(readline("prompt"));'
then
READLINE_COMPILE="-DFEAT_READLINE=1 $readline_inc"
add_def FEAT_READLINE
READLINE_COMPILE="$readline_inc"
READLINE_LINK="$readline_lib $ncurses_lib -lreadline -lncurses"
fi
fi
fi
HASH_OBJ="hash_intmd5.o"
HASH_COMPILE=""
HASH_LINK=""
if [ $try_nss = "1" ]; then
test_cflags="`pkg-config --cflags nss`"
test_link="`pkg-config --libs-only-L nss` -lfreebl3"
if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
"$test_cflags" "$test_link" \
'NSSLOWHASH_Begin(NSSLOWHASH_NewContext(NSSLOW_Init(), HASH_AlgSHA512));'
then
HASH_OBJ="hash_nss.o"
HASH_COMPILE="$test_cflags"
HASH_LINK="$test_link"
add_def GENERATE_SHA1_KEY
fi
fi
if [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]; then
if test_code 'tomcrypt' 'tomcrypt.h' '-I/usr/include/tomcrypt' '-ltomcrypt' \
'hash_memory_multi(find_hash("md5"), NULL, NULL, NULL, 0, NULL, 0);'
then
HASH_OBJ="hash_tomcrypt.o"
HASH_COMPILE="-I/usr/include/tomcrypt"
HASH_LINK="-ltomcrypt"
add_def GENERATE_SHA1_KEY
fi
fi
SYSCONFDIR=/etc
if [ "x$SETSYSCONFDIR" != "x" ]; then
SYSCONFDIR=$SETSYSCONFDIR
@@ -478,26 +583,51 @@ if [ "x$SETDOCDIR" != "x" ]; then
DOCDIR=$SETDOCDIR
fi
sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
s%@CC@%${MYCC}%;\
s%@CFLAGS@%${MYCFLAGS}%;\
s%@CCWARNFLAGS@%${CCWARNFLAGS}%;\
s%@CPPFLAGS@%${CPPFLAGS}%;\
s%@LIBS@%${LIBS}%;\
s%@LDFLAGS@%${MYLDFLAGS}%;\
s%@EXTRA_LIBS@%${EXTRA_LIBS}%;\
s%@SYSDEFS@%${SYSDEFS}%;\
s%@EXTRA_DEFS@%${EXTRA_DEFS}%;\
s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\
s%@READLINE_COMPILE@%${READLINE_COMPILE}%;\
s%@READLINE_LINK@%${READLINE_LINK}%;\
s%@SYSCONFDIR@%${SYSCONFDIR}%;\
s%@BINDIR@%${BINDIR}%;\
s%@SBINDIR@%${SBINDIR}%;\
s%@DOCDIR@%${DOCDIR}%;\
s%@MANDIR@%${MANDIR}%;\
s%@INFODIR@%${INFODIR}%;"\
< Makefile.in > Makefile
LOCALSTATEDIR=/var
if [ "x$SETLOCALSTATEDIR" != "x" ]; then
LOCALSTATEDIR=$SETLOCALSTATEDIR
fi
CHRONYVARDIR=${LOCALSTATEDIR}/lib/chrony
if [ "x$SETCHRONYVARDIR" != "x" ]; then
CHRONYVARDIR=$SETCHRONYVARDIR
fi
add_def DEFAULT_CONF_FILE "\"$SYSCONFDIR/chrony.conf\""
add_def MAIL_PROGRAM "\"$mail_program\""
if [ -f version.txt ]; then
add_def CHRONY_VERSION "\"`cat version.txt`\""
else
add_def CHRONY_VERSION "\"DEVELOPMENT\""
fi
for f in Makefile chrony.conf.5 chrony.texi chronyc.1 chronyd.8
do
echo Creating $f
sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
s%@CC@%${MYCC}%;\
s%@CFLAGS@%${MYCFLAGS}%;\
s%@CPPFLAGS@%${CPPFLAGS}%;\
s%@LIBS@%${LIBS}%;\
s%@LDFLAGS@%${MYLDFLAGS}%;\
s%@EXTRA_LIBS@%${EXTRA_LIBS}%;\
s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\
s%@READLINE_COMPILE@%${READLINE_COMPILE}%;\
s%@READLINE_LINK@%${READLINE_LINK}%;\
s%@HASH_OBJ@%${HASH_OBJ}%;\
s%@HASH_LINK@%${HASH_LINK}%;\
s%@HASH_COMPILE@%${HASH_COMPILE}%;\
s%@SYSCONFDIR@%${SYSCONFDIR}%;\
s%@BINDIR@%${BINDIR}%;\
s%@SBINDIR@%${SBINDIR}%;\
s%@DOCDIR@%${DOCDIR}%;\
s%@MANDIR@%${MANDIR}%;\
s%@INFODIR@%${INFODIR}%;\
s%@LOCALSTATEDIR@%${LOCALSTATEDIR}%;\
s%@CHRONYVARDIR@%${CHRONYVARDIR}%;"\
< ${f}.in > $f
done
# =======================================================================
# vim:et:sw=2:ht=2:sts=2:fdm=marker:cms=#%s

View File

@@ -40,21 +40,21 @@
# more 'NTP servers'. You will probably find that your Internet Service
# Provider or company have one or more NTP servers that you can specify.
# Failing that, there are a lot of public NTP servers. There is a list
# you can access at
# http://www.eecis.udel.edu/~mills/ntp/servers.htm.
# you can access at http://support.ntp.org/bin/view/Servers/WebHome or
# you can use servers from the pool.ntp.org project.
! server ntp0.your-isp.com
! server ntp1.your-isp.com
! server ntp.public-server.org
! server 0.pool.ntp.org iburst
! server 1.pool.ntp.org iburst
! server 2.pool.ntp.org iburst
# However, for dial-up use you probably want these instead. The word
# 'offline' means that the server is not visible at boot time. Use
# chronyc's 'online' command to tell chronyd that these servers have
# become visible after you go on-line.
! server ntp0.your-isp.com offline
! server ntp1.your-isp.com offline
! server ntp.public-server.org offline
! server 0.pool.ntp.org offline
! server 1.pool.ntp.org offline
! server 2.pool.ntp.org offline
# You may want to specify NTP 'peers' instead. If you run a network
# with a lot of computers and want several computers running chrony to
@@ -89,7 +89,7 @@
# immediately so that it doesn't gain or lose any more time. You
# generally want this, so it is uncommented.
driftfile /etc/chrony.drift
driftfile /var/lib/chrony/drift
# If you want to use the program called chronyc to configure aspects of
# chronyd's operation once it is running (e.g. tell it the Internet link
@@ -122,7 +122,7 @@ commandkey 1
# Enable these two options to use this.
! dumponexit
! dumpdir /var/log/chrony
! dumpdir /var/lib/chrony
# chronyd writes its process ID to a file. If you try to start a second
# copy of chronyd, it will detect that the process named in the file is
@@ -133,17 +133,16 @@ commandkey 1
#######################################################################
### INITIAL CLOCK CORRECTION
# This option is only useful if your NTP servers are visible at boot
# time. This probably means you are on a LAN. If so, the following
# option will choose the best-looking of the servers and correct the
# system time to that. The value '10' means that if the error is less
# This option is useful to quickly correct the clock on start if it's
# off by a large amount. The value '10' means that if the error is less
# than 10 seconds, it will be gradually removed by speeding up or
# slowing down your computer's clock until it is correct. If the error
# is above 10 seconds, an immediate time jump will be applied to correct
# it. Some software can get upset if the system clock jumps (especially
# backwards), so be careful!
# it. The value '1' means the step is allowed only on the first update
# of the clock. Some software can get upset if the system clock jumps
# (especially backwards), so be careful!
! initstepslew 10 ntp0.your-company.com ntp1.your-company.com ntp2.your-company.com
! makestep 10 1
#######################################################################
### LOGGING
@@ -255,13 +254,6 @@ commandkey 1
# put into chronyc to allow you to modify chronyd's parameters. By
# default all you can do is view information about chronyd's operation.
# Some people have reported that the need the following line to allow
# chronyc to work even on the same machine. This should not be
# necessary, and the problem is being investigated. You can leave this
# line enabled, as it's benign otherwise.
cmdallow 127.0.0.1
#######################################################################
### REAL TIME CLOCK
# chronyd can characterise the system's real-time clock. This is the
@@ -273,7 +265,7 @@ cmdallow 127.0.0.1
# You need to have 'enhanced RTC support' compiled into your Linux
# kernel. (Note, these options apply only to Linux.)
! rtcfile /etc/chrony.rtc
! rtcfile /var/lib/chrony/rtc
# Your RTC can be set to keep Universal Coordinated Time (UTC) or local
# time. (Local time means UTC +/- the effect of your timezone.) If you

View File

@@ -15,12 +15,16 @@ driftfile /var/lib/chrony/drift
rtcsync
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 100 seconds.
makestep 100 3
# if the adjustment is larger than 10 seconds.
makestep 10 3
# Allow client access from local network.
# Allow NTP client access from local network.
#allow 192.168/16
# Listen for commands only on localhost.
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
# Serve time even if not synchronized to any NTP server.
#local stratum 10
@@ -29,6 +33,9 @@ keyfile /etc/chrony.keys
# Specify the key used as password for chronyc.
commandkey 1
# Generate command key if missing.
generatecommandkey
# Disable logging of client accesses.
noclientlog

View File

@@ -1,26 +1,29 @@
#######################################################################
#
# This is an example chrony keys file. You should copy it to /etc/chrony.keys
# after editing it to set up the key(s) you want to use. In most situations,
# you will require a single key (the 'commandkey') so that you can supply a
# password to chronyc to enable you to modify chronyd's operation whilst it is
# running.
# after editing it to set up the key(s) you want to use. It should be readable
# only by root or the user chronyd drops the root privileges to. In most
# situations, you will require a single key (the 'commandkey') so that you can
# supply a password to chronyc to enable you to modify chronyd's operation
# whilst it is running.
#
# Copyright 2002 Richard P. Curnow
#
#######################################################################
# A valid key line looks like this
######################################################################
1 a_key
# Examples of valid keys:
# It must consist of an integer, followed by whitespace, followed by a block of
# text with no spaces in it. (You cannot put a space in a key). If you wanted
# to use the above line as your commandkey (i.e. chronyc password), you would
# put the following line into chrony.conf (remove the # from the start):
#1 ALongAndRandomPassword
#2 MD5 HEX:B028F91EA5C38D06C2E140B26C7F41EC
#3 SHA1 HEX:1DC764E0791B11FA67EFC7ECBC4B0D73F68A070C
# commandkey 1
# The keys should be random for maximum security. If you wanted to use a key
# with ID 1 as your commandkey (i.e. chronyc password) you would put
# "commandkey 1" into chrony.conf. If no commandkey is present in the keys
# file and the generatecommandkey directive is specified in chrony.conf,
# a random commandkey will be generated and added to the keys file
# automatically on chronyd start.
# You might want to define more keys if you use the MD5 authentication facility
# You might want to define more keys if you use the authentication facility
# in the network time protocol to authenticate request/response packets between
# trusted clients and servers.

88
faq.txt
View File

@@ -68,7 +68,7 @@ support hardware reference clocks to your computer, then xntpd will work fine.
Apart from not supporting hardware clocks, chrony will work fine too.
If your computer connects to the 'net for 5 minutes once a day (or something
like that), or you turn your (Linux v2.0) computer off when you're not using
like that), or you turn your Linux computer off when you're not using
it, or you want to use NTP on an isolated network with no hardware clocks in
sight, chrony will work much better for you.
@@ -96,56 +96,6 @@ at all, I found xntpd gave me no help with managing the local clock's
gain/loss rate on the NTP master node (which I set from my watch). I
added some automated support in chrony to deal with this.
S: Compilation issues
Q:How do I apply source patches?
Sometimes we release source patches rather than a full version when we need to
provide a fix for small problems. Supposing you have chrony-1.X.tar.gz and a
source patch chrony-1.X-1.X.1.gz. The steps required are:
tar xzvf ../chrony-1.X.tar.gz
cd chrony-1.X
gunzip < ../../chrony-1.X-1.X.1.gz | patch -p1
./configure
make
make install
Q:Can I compile chrony with an ANSI-C compiler that is not GCC v2.x?
I have had reports that chrony can be compiled with GCC v1.42, by using the
following trick when running make
make CC='gcc -D__FUNCTION__=\"function_not_available\"'
(this gets around the lack of a __FUNCTION__ macro in GCC v1.)
The same trick may be enough to allow other compilers to be used.
Q: I get errors like 'client.c:44: readline/readline.h: file not found'
Read the section about 'readline' in the INSTALL file or in chrony.txt. You
may need to disable readline support (e.g. if you haven't got readline
installed at all, or just don't want it), or specify the location of the
readline files (e.g. if you've installed them in a non-standard place).
Q: I have RedHat 7.3 and can't compile rtc_linux.c (error in spinlock.h)
The following solution has been found for this. Enter the following 3 commands
(as root):
cd /usr/include/
mv linux linux.rh
ln -s /usr/src/linux/include/linux ./linux
The problem seems to be that RedHat provide their own kernel header files in
/usr/include/linux. Besides differing from those used by your current kernel,
if you compiled it yourself, they also seem to have been changed in a way that
causes a problem compiling chrony. Chrony compiles fine with standard kernel
header files.
There have also been reports that just replacing the file
/usr/src/linux/spinlock.h by the equivalent file from a vanilla kernel source
tree is sufficient to fix the problem.
Note : from version 1.21 onwards, this problem no longer exists. The kernel
header files are no longer included.
S: Selection of NTP servers
Q: I have several computers on a LAN. Should I make one the master, or make them all clients of an external server?
I think the best configuration is to make one computer the master, with the
@@ -201,34 +151,12 @@ Do you have a 'local stratum X' directive in the chrony.conf file? If X is
lower than the stratum of the server you're trying to use, this situation will
arise. You should always make X quite high (e.g. 10) in this directive.
S: Issues with chronyd
Q: chronyd crashes after a syslog message "adjtimex failed for set frequency"
The usual cause is that the kernel is running with a different value of 'HZ'
(the timer interrupt rate) than the value that was found in the kernel header
files when chrony was compiled. The chrony.conf file can include options to
modify the HZ value (see the discussion of linux_hz and linux_freq_scale in the
documentation), however the problem is to find the value of HZ being used.
S: Issues with chronyc
Q: I keep getting the error '510 No command access from this host --- Reply not authenticated'.
Q: I keep getting the error '506 Cannot talk to daemon'.
Make sure that the chrony.conf file (on the computer where chronyd is running)
has a 'cmdallow' entry for the computer you are running chronyc on. This
shouldn't be necessary for localhost, but some people still seem to need an
entry like 'cmdallow 127.0.0.1'. (It would be good to understand why problem
only affects some people).
Q: I cannot log in from chronyc to carry out privileged tasks.
This is the second most common problem.
Perhaps your /etc/chrony.keys file is badly formatted. Make sure that the
final line has a line feed at the end, otherwise the key on that line will work
as though the last character is missing. (Note, this bug was fixed in version
1.16.)
Q: When I enter a command and hit &lt;Return&gt;, chronyc hangs
This probably means that chronyc cannot communicate with chronyd.
isn't necessary for localhost.
Perhaps chronyd is not running. Try using the ps command (e.g. on Linux, 'ps
-auxw') to see if it's running. Or try 'netstat -a' and see if the ports
@@ -268,14 +196,6 @@ For the real time clock support to work, you need the following three things:
* enhanced RTC support compiled into the kernel
* an 'rtcfile' directive in your chrony.conf file.
S: Problems with isolated networks.
Q: When I use the 'settime' command, chronyd crashes.
If you enter times that are too far away from the real time, chronyd will
think the system clock runs fast or slow by an excessive amount. The required
compensation factor will be outside the bounds for the adjtimex() system call.
chronyd will crash when it tries to apply such an excessive adjustment.
S: Microsoft Windows
Q: Does chrony support Windows?
@@ -338,7 +258,7 @@ The program needs to see the definitions of structures used to interact with
the real time clock (via /dev/rtc) and with the adjtimex() system call. Sadly
this has led to a number of compilation problems with newer kernels which have
been increasingly hard to fix in a way that makes the code compilable on all
Linux kernel versions (from 2.0 up anyway, I doubt 1.x still works.) Hopefully
Linux kernel versions. Hopefully
the situation will not deteriorate further with future kernel versions.
Q: I get "Could not open /dev/rtc, Device or resource busy" in my syslog file.

41
hash.h Normal file
View File

@@ -0,0 +1,41 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for crypto hashing.
*/
#ifndef GOT_HASH_H
#define GOT_HASH_H
/* length of hash values produced by SHA512 */
#define MAX_HASH_LENGTH 64
extern int HSH_GetHashId(const char *name);
extern unsigned int HSH_Hash(int id,
const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len);
#endif

64
hash_intmd5.c Normal file
View File

@@ -0,0 +1,64 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Routines implementing crypto hashing using internal MD5 implementation.
*/
#include "config.h"
#include "sysincl.h"
#include "hash.h"
#include "memory.h"
#include "md5.c"
static MD5_CTX ctx;
int
HSH_GetHashId(const char *name)
{
/* only MD5 is supported */
if (strcmp(name, "MD5"))
return -1;
return 0;
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
{
if (out_len < 16)
return 0;
MD5Init(&ctx);
MD5Update(&ctx, in1, in1_len);
if (in2)
MD5Update(&ctx, in2, in2_len);
MD5Final(&ctx);
memcpy(out, ctx.digest, 16);
return 16;
}

89
hash_nss.c Normal file
View File

@@ -0,0 +1,89 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Routines implementing crypto hashing using NSSLOWHASH API of the NSS library.
*/
#include <nss.h>
#include <hasht.h>
#include <nsslowhash.h>
/* #include "config.h" */
#include "hash.h"
static NSSLOWInitContext *ictx;
struct hash {
HASH_HashType type;
const char *name;
NSSLOWHASHContext *context;
};
static struct hash hashes[] = {
{ HASH_AlgMD5, "MD5", NULL },
{ HASH_AlgSHA1, "SHA1", NULL },
{ HASH_AlgSHA256, "SHA256", NULL },
{ HASH_AlgSHA384, "SHA384", NULL },
{ HASH_AlgSHA512, "SHA512", NULL },
{ 0, NULL, NULL }
};
int
HSH_GetHashId(const char *name)
{
int i;
for (i = 0; hashes[i].name; i++) {
if (!strcmp(name, hashes[i].name))
break;
}
if (!hashes[i].name)
return -1; /* not found */
if (!ictx && !(ictx = NSSLOW_Init()))
return -1; /* couldn't init NSS */
if (!hashes[i].context &&
!(hashes[i].context = NSSLOWHASH_NewContext(ictx, hashes[i].type)))
return -1; /* couldn't init hash */
return i;
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
{
unsigned int ret;
NSSLOWHASH_Begin(hashes[id].context);
NSSLOWHASH_Update(hashes[id].context, in1, in1_len);
if (in2)
NSSLOWHASH_Update(hashes[id].context, in2, in2_len);
NSSLOWHASH_End(hashes[id].context, out, &ret, out_len);
return ret;
}

116
hash_tomcrypt.c Normal file
View File

@@ -0,0 +1,116 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Routines implementing crypto hashing using tomcrypt library.
*/
#include <tomcrypt.h>
#include "config.h"
#include "hash.h"
struct hash {
const char *name;
const char *int_name;
const struct ltc_hash_descriptor *desc;
};
static const struct hash hashes[] = {
{ "MD5", "md5", &md5_desc },
#ifdef LTC_RIPEMD128
{ "RMD128", "rmd128", &rmd128_desc },
#endif
#ifdef LTC_RIPEMD160
{ "RMD160", "rmd160", &rmd160_desc },
#endif
#ifdef LTC_RIPEMD256
{ "RMD256", "rmd256", &rmd256_desc },
#endif
#ifdef LTC_RIPEMD320
{ "RMD320", "rmd320", &rmd320_desc },
#endif
#ifdef LTC_SHA1
{ "SHA1", "sha1", &sha1_desc },
#endif
#ifdef LTC_SHA256
{ "SHA256", "sha256", &sha256_desc },
#endif
#ifdef LTC_SHA384
{ "SHA384", "sha384", &sha384_desc },
#endif
#ifdef LTC_SHA512
{ "SHA512", "sha512", &sha512_desc },
#endif
#ifdef LTC_TIGER
{ "TIGER", "tiger", &tiger_desc },
#endif
#ifdef LTC_WHIRLPOOL
{ "WHIRLPOOL", "whirlpool", &whirlpool_desc },
#endif
{ NULL, NULL, NULL }
};
int
HSH_GetHashId(const char *name)
{
int i, h;
for (i = 0; hashes[i].name; i++) {
if (!strcmp(name, hashes[i].name))
break;
}
if (!hashes[i].name)
return -1; /* not found */
h = find_hash(hashes[i].int_name);
if (h >= 0)
return h; /* already registered */
/* register and try again */
register_hash(hashes[i].desc);
return find_hash(hashes[i].int_name);
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
{
unsigned long len;
int r;
len = out_len;
if (in2)
r = hash_memory_multi(id, out, &len,
in1, (unsigned long)in1_len, in2, (unsigned long)in2_len, NULL, 0);
else
r = hash_memory(id, in1, in1_len, out, &len);
if (r != CRYPT_OK)
return 0;
return len;
}

320
keys.c
View File

@@ -3,6 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2012-2013
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,18 +26,25 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "sysincl.h"
#include "keys.h"
#include "cmdparse.h"
#include "conf.h"
#include "memory.h"
#include "util.h"
#include "local.h"
#include "logging.h"
typedef struct {
unsigned long id;
char *val;
int len;
int hash_id;
int auth_delay;
} Key;
#define MAX_KEYS 256
@@ -45,13 +53,71 @@ static int n_keys;
static Key keys[MAX_KEYS];
static int command_key_valid;
static int command_key_pos;
static int command_key_id;
static int cache_valid;
static unsigned long cache_key_id;
static int cache_key_pos;
/* ================================================== */
static int
generate_key(unsigned long key_id)
{
#ifdef GENERATE_SHA1_KEY
unsigned char key[20];
const char *hashname = "SHA1";
#else
unsigned char key[16];
const char *hashname = "MD5";
#endif
const char *key_file, *rand_dev = "/dev/urandom";
FILE *f;
struct stat st;
int i;
key_file = CNF_GetKeysFile();
if (!key_file)
return 0;
f = fopen(rand_dev, "r");
if (!f || fread(key, sizeof (key), 1, f) != 1) {
if (f)
fclose(f);
LOG_FATAL(LOGF_Keys, "Could not read %s", rand_dev);
return 0;
}
fclose(f);
f = fopen(key_file, "a");
if (!f) {
LOG_FATAL(LOGF_Keys, "Could not open keyfile %s for writing", key_file);
return 0;
}
/* Make sure the keyfile is not world-readable */
if (stat(key_file, &st) || chmod(key_file, st.st_mode & 0770)) {
fclose(f);
LOG_FATAL(LOGF_Keys, "Could not change permissions of keyfile %s", key_file);
return 0;
}
fprintf(f, "\n%lu %s HEX:", key_id, hashname);
for (i = 0; i < sizeof (key); i++)
fprintf(f, "%02hhX", key[i]);
fprintf(f, "\n");
fclose(f);
/* Erase the key from stack */
memset(key, 0, sizeof (key));
LOG(LOGS_INFO, LOGF_Keys, "Generated key %lu", key_id);
return 1;
}
/* ================================================== */
void
KEY_Initialise(void)
{
@@ -59,7 +125,11 @@ KEY_Initialise(void)
command_key_valid = 0;
cache_valid = 0;
KEY_Reload();
return;
if (CNF_GetGenerateCommandKey() && !KEY_KeyKnown(KEY_GetCommandKey())) {
if (generate_key(KEY_GetCommandKey()))
KEY_Reload();
}
}
/* ================================================== */
@@ -67,8 +137,37 @@ KEY_Initialise(void)
void
KEY_Finalise(void)
{
/* Nothing to do */
return;
}
/* ================================================== */
static int
determine_hash_delay(int key_id)
{
NTP_Packet pkt;
struct timeval before, after;
unsigned long usecs, min_usecs=0;
int i;
for (i = 0; i < 10; i++) {
LCL_ReadRawTime(&before);
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_SIZE,
(unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
LCL_ReadRawTime(&after);
usecs = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec);
if (i == 0 || usecs < min_usecs) {
min_usecs = usecs;
}
}
#if 0
LOG(LOGS_INFO, LOGF_Keys, "authentication delay for key %lu: %d useconds", key_id, min_usecs);
#endif
/* Add on a bit extra to allow for copying, conversions etc */
return min_usecs + (min_usecs >> 4);
}
/* ================================================== */
@@ -93,61 +192,84 @@ compare_keys_by_id(const void *a, const void *b)
/* ================================================== */
#define KEYLEN 2047
#define SKEYLEN "2047"
void
KEY_Reload(void)
{
int i, len1;
char *key_file;
int i, line_number;
FILE *in;
unsigned long key_id;
char line[KEYLEN+1], keyval[KEYLEN+1];
char line[2048], *keyval, *key_file;
const char *hashname;
for (i=0; i<n_keys; i++) {
Free(keys[i].val);
}
n_keys = 0;
key_file = CNF_GetKeysFile();
if (key_file) {
in = fopen(key_file, "r");
if (in) {
while (fgets(line, sizeof(line), in)) {
len1 = strlen(line) - 1;
/* Guard against removing last character of the line
* if the last line of the file is missing an end-of-line */
if (line[len1] == '\n') {
line[len1] = '\0';
}
if (sscanf(line, "%lu%" SKEYLEN "s", &key_id, keyval) == 2) {
keys[n_keys].id = key_id;
keys[n_keys].len = strlen(keyval);
keys[n_keys].val = MallocArray(char, 1 + keys[n_keys].len);
strcpy(keys[n_keys].val, keyval);
n_keys++;
}
}
fclose(in);
/* Sort keys into order. Note, if there's a duplicate, it is
arbitrary which one we use later - the user should have been
more careful! */
qsort((void *) keys, n_keys, sizeof(Key), compare_keys_by_id);
}
}
command_key_valid = 0;
cache_valid = 0;
return;
key_file = CNF_GetKeysFile();
line_number = 0;
if (!key_file)
return;
in = fopen(key_file, "r");
if (!in) {
LOG(LOGS_WARN, LOGF_Keys, "Could not open keyfile %s", key_file);
return;
}
while (fgets(line, sizeof (line), in)) {
line_number++;
CPS_NormalizeLine(line);
if (!*line)
continue;
if (!CPS_ParseKey(line, &key_id, &hashname, &keyval)) {
LOG(LOGS_WARN, LOGF_Keys, "Could not parse key at line %d in file %s", line_number, key_file);
continue;
}
keys[n_keys].hash_id = HSH_GetHashId(hashname);
if (keys[n_keys].hash_id < 0) {
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %lu", key_id);
continue;
}
keys[n_keys].len = UTI_DecodePasswordFromText(keyval);
if (!keys[n_keys].len) {
LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %lu", key_id);
continue;
}
keys[n_keys].id = key_id;
keys[n_keys].val = MallocArray(char, keys[n_keys].len);
memcpy(keys[n_keys].val, keyval, keys[n_keys].len);
n_keys++;
}
fclose(in);
/* Sort keys into order. Note, if there's a duplicate, it is
arbitrary which one we use later - the user should have been
more careful! */
qsort((void *) keys, n_keys, sizeof(Key), compare_keys_by_id);
/* Check for duplicates */
for (i = 1; i < n_keys; i++) {
if (keys[i - 1].id == keys[i].id) {
LOG(LOGS_WARN, LOGF_Keys, "Detected duplicate key %lu", key_id);
}
}
/* Erase any passwords from stack */
memset(line, 0, sizeof (line));
for (i=0; i<n_keys; i++) {
keys[i].auth_delay = determine_hash_delay(keys[i].id);
}
}
/* ================================================== */
@@ -170,30 +292,8 @@ lookup_key(unsigned long id)
/* ================================================== */
void
KEY_CommandKey(char **key, int *len)
{
unsigned long command_key_id;
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
command_key_pos = lookup_key(command_key_id);
command_key_valid = 1;
}
if (command_key_pos >= 0) {
*key = keys[command_key_pos].val;
*len = keys[command_key_pos].len;
} else {
*key = "";
*len = 0;
}
}
/* ================================================== */
int
KEY_GetKey(unsigned long key_id, char **key, int *len)
static int
get_key_pos(unsigned long key_id)
{
if (!cache_valid || key_id != cache_key_id) {
cache_valid = 1;
@@ -201,15 +301,19 @@ KEY_GetKey(unsigned long key_id, char **key, int *len)
cache_key_id = key_id;
}
if (cache_key_pos >= 0) {
*key = keys[cache_key_pos].val;
*len = keys[cache_key_pos].len;
return 1;
} else {
*key = "";
*len = 0;
return 0;
return cache_key_pos;
}
/* ================================================== */
unsigned long
KEY_GetCommandKey(void)
{
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
}
return command_key_id;
}
/* ================================================== */
@@ -237,3 +341,57 @@ KEY_KeyKnown(unsigned long key_id)
}
}
}
/* ================================================== */
int
KEY_GetAuthDelay(unsigned long key_id)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return keys[key_pos].auth_delay;
}
/* ================================================== */
int
KEY_GenerateAuth(unsigned long key_id, const unsigned char *data, int data_len,
unsigned char *auth, int auth_len)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return UTI_GenerateNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}
/* ================================================== */
int
KEY_CheckAuth(unsigned long key_id, const unsigned char *data, int data_len,
const unsigned char *auth, int auth_len)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return UTI_CheckNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}

8
keys.h
View File

@@ -32,9 +32,15 @@ extern void KEY_Finalise(void);
extern void KEY_Reload(void);
extern void KEY_CommandKey(char **key, int *len);
extern unsigned long KEY_GetCommandKey(void);
extern int KEY_GetKey(unsigned long key_id, char **key, int *len);
extern int KEY_KeyKnown(unsigned long key_id);
extern int KEY_GetAuthDelay(unsigned long key_id);
extern int KEY_GenerateAuth(unsigned long key_id, const unsigned char *data,
int data_len, unsigned char *auth, int auth_len);
extern int KEY_CheckAuth(unsigned long key_id, const unsigned char *data,
int data_len, const unsigned char *auth, int auth_len);
#endif /* GOT_KEYS_H */

51
local.c
View File

@@ -28,8 +28,9 @@
They interface with the system specific driver files in sys_*.c
*/
#include <assert.h>
#include <stddef.h>
#include "config.h"
#include "sysincl.h"
#include "conf.h"
#include "local.h"
@@ -130,8 +131,6 @@ calculate_sys_precision(void)
precision_log--;
best_dusec *= 2;
}
return;
}
/* ================================================== */
@@ -165,7 +164,6 @@ LCL_Initialise(void)
void
LCL_Finalise(void)
{
return;
}
/* ================================================== */
@@ -218,14 +216,11 @@ LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything
new_entry->prev = change_list.prev;
change_list.prev->next = new_entry;
change_list.prev = new_entry;
return;
}
/* ================================================== */
/* Remove a handler */
extern
void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything)
{
@@ -249,8 +244,6 @@ void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *
ptr->prev->next = ptr->next;
free(ptr);
return;
}
/* ================================================== */
@@ -277,8 +270,6 @@ LCL_AddDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anythi
new_entry->prev = dispersion_notify_list.prev;
dispersion_notify_list.prev->next = new_entry;
dispersion_notify_list.prev = new_entry;
return;
}
/* ================================================== */
@@ -308,8 +299,6 @@ void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void
ptr->prev->next = ptr->next;
free(ptr);
return;
}
/* ================================================== */
@@ -356,14 +345,14 @@ LCL_GetOffsetCorrection(struct timeval *raw, double *correction, double *err)
}
/* ================================================== */
/* This is just a simple passthrough of the system specific routine */
/* Return current frequency */
double
LCL_ReadAbsoluteFrequency(void)
{
double freq;
freq = (*drv_read_freq)();
freq = current_freq_ppm;
/* Undo temperature compensation */
if (temp_comp_ppm != 0.0) {
@@ -441,7 +430,7 @@ LCL_AccumulateDeltaFrequency(double dfreq)
/* ================================================== */
void
LCL_AccumulateOffset(double offset)
LCL_AccumulateOffset(double offset, double corr_rate)
{
ChangeListEntry *ptr;
struct timeval raw, cooked;
@@ -452,7 +441,7 @@ LCL_AccumulateOffset(double offset)
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
(*drv_accrue_offset)(offset);
(*drv_accrue_offset)(offset, corr_rate);
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
@@ -487,7 +476,23 @@ LCL_ApplyStepOffset(double offset)
/* ================================================== */
void
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
double offset, double dispersion)
{
ChangeListEntry *ptr;
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
(ptr->handler)(raw, cooked, 0.0, offset, 1, ptr->anything);
}
lcl_InvokeDispersionNotifyHandlers(dispersion);
}
/* ================================================== */
void
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
{
ChangeListEntry *ptr;
struct timeval raw, cooked;
@@ -514,7 +519,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 + old_freq_ppm);
(*drv_accrue_offset)(doffset);
(*drv_accrue_offset)(doffset, corr_rate);
/* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
@@ -559,8 +564,6 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Local, "Local freq=%.3fppm", current_freq_ppm);
#endif
return;
}
/* ================================================== */
@@ -580,7 +583,7 @@ LCL_MakeStep(double threshold)
return 0;
/* Cancel remaining slew and make the step */
LCL_AccumulateOffset(correction);
LCL_AccumulateOffset(correction, 0.0);
LCL_ApplyStepOffset(-correction);
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.3f seconds", correction);
@@ -596,8 +599,6 @@ LCL_SetLeap(int leap)
if (drv_set_leap) {
(drv_set_leap)(leap);
}
return;
}
/* ================================================== */

12
local.h
View File

@@ -138,9 +138,10 @@ extern void LCL_AccumulateDeltaFrequency(double dfreq);
/* Routine to apply an offset (in seconds) to the local clock. The
argument should be positive to move the clock backwards (i.e. the
local clock is currently fast of true time), or negative to move it
forwards (i.e. it is currently slow of true time). */
forwards (i.e. it is currently slow of true time). Provided is also
a suggested correction rate (correction time * offset). */
extern void LCL_AccumulateOffset(double offset);
extern void LCL_AccumulateOffset(double offset, double corr_rate);
/* Routine to apply an immediate offset by doing a sudden step if
possible. (Intended for use after an initial estimate of offset has
@@ -151,9 +152,14 @@ extern void LCL_AccumulateOffset(double offset);
extern void LCL_ApplyStepOffset(double offset);
/* Routine to invoke notify handlers on an unexpected time jump
in system clock */
extern void LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
double offset, double dispersion);
/* Perform the combination of modifying the frequency and applying
a slew, in one easy step */
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset);
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
/* Routine to read the system precision as a log to base 2 value. */
extern int LCL_GetSysPrecisionAsLog(void);

View File

@@ -41,8 +41,9 @@ typedef double (*lcl_ReadFrequencyDriver)(void);
typedef double (*lcl_SetFrequencyDriver)(double freq_ppm);
/* System driver to accrue an offset. A positive argument means slew
the clock forwards. */
typedef void (*lcl_AccrueOffsetDriver)(double offset);
the clock forwards. The suggested correction rate of time to correct the
offset is given in 'corr_rate'. */
typedef void (*lcl_AccrueOffsetDriver)(double offset, double corr_rate);
/* System driver to apply a step offset. A positive argument means step
the clock forwards. */

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
* Copyright (C) Miroslav Lichvar 2011-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,9 +25,10 @@
Module to handle logging of diagnostic information
*/
#include "config.h"
#include "sysincl.h"
#include "main.h"
#include "conf.h"
#include "logging.h"
#include "mkdirpp.h"
@@ -39,6 +40,8 @@ static int initialised = 0;
static int system_log = 0;
static int parent_fd = 0;
static time_t last_limited = 0;
#ifdef WINNT
@@ -70,8 +73,6 @@ LOG_Initialise(void)
#ifdef WINNT
logfile = fopen("./chronyd.err", "a");
#endif
return;
}
/* ================================================== */
@@ -93,7 +94,6 @@ LOG_Finalise(void)
LOG_CycleLogFiles();
initialised = 0;
return;
}
/* ================================================== */
@@ -128,7 +128,6 @@ LOG_Line_Function(LOG_Severity severity, LOG_Facility facility, const char *form
fprintf(stderr, "%s\n", buf);
}
#endif
return;
}
/* ================================================== */
@@ -152,11 +151,13 @@ LOG_Fatal_Function(LOG_Facility facility, const char *format, ...)
} else {
fprintf(stderr, "Fatal error : %s\n", buf);
}
if (parent_fd) {
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
; /* Not much we can do here */
}
#endif
MAI_CleanupAndExit();
return;
exit(1);
}
/* ================================================== */
@@ -177,7 +178,6 @@ LOG_Position(const char *filename, int line_number, const char *function_name)
fprintf(stderr, "%s:%d:(%s)[%s] ", filename, line_number, function_name, buf);
}
#endif
return;
}
/* ================================================== */
@@ -194,6 +194,23 @@ LOG_OpenSystemLog(void)
/* ================================================== */
void
LOG_SetParentFd(int fd)
{
parent_fd = fd;
}
/* ================================================== */
void
LOG_CloseParentFd()
{
if (parent_fd > 0)
close(parent_fd);
}
/* ================================================== */
int
LOG_RateLimited(void)
{
@@ -280,14 +297,10 @@ LOG_CreateLogFileDir(void)
{
const char *logdir;
if (n_filelogs <= 0)
return;
logdir = CNF_GetLogDir();
if (!mkdir_and_parents(logdir)) {
LOG(LOGS_ERR, LOGF_Logging, "Could not create directory %s", logdir);
n_filelogs = 0;
}
}

View File

@@ -54,6 +54,7 @@ typedef enum {
LOGF_CmdMon,
LOGF_Acquire,
LOGF_Manual,
LOGF_Keys,
LOGF_Logging,
LOGF_Rtc,
LOGF_Regress,
@@ -85,6 +86,12 @@ extern void LOG_Position(const char *filename, int line_number, const char *func
/* Log messages to syslog instead of stderr */
extern void LOG_OpenSystemLog(void);
/* Send fatal message also to the foreground process */
extern void LOG_SetParentFd(int fd);
/* Close the pipe to the foreground process so it can exit */
extern void LOG_CloseParentFd(void);
/* Return zero once per 10 seconds */
extern int LOG_RateLimited(void);

86
main.c
View File

@@ -4,6 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,6 +26,8 @@
The main program
*/
#include "config.h"
#include "sysincl.h"
#include "main.h"
@@ -43,7 +46,6 @@
#include "keys.h"
#include "acquire.h"
#include "manual.h"
#include "version.h"
#include "rtc.h"
#include "refclock.h"
#include "clientlog.h"
@@ -86,13 +88,13 @@ MAI_CleanupAndExit(void)
TMC_Finalise();
MNL_Finalise();
ACQ_Finalise();
KEY_Finalise();
CLG_Finalise();
NSR_Finalise();
NCR_Finalise();
BRD_Finalise();
SST_Finalise();
REF_Finalise();
KEY_Finalise();
RCL_Finalise();
SRC_Finalise();
RTC_Finalise();
@@ -123,6 +125,8 @@ signal_cleanup(int x)
static void
post_acquire_hook(void *anything)
{
/* Close the pipe to the foreground process so it can exit */
LOG_CloseParentFd();
CNF_AddSources();
CNF_AddBroadcasts();
@@ -213,7 +217,13 @@ go_daemon(void)
#else
int pid, fd;
int pid, fd, pipefd[2];
/* Create pipe which will the daemon use to notify the grandparent
when it's initialised or send an error message */
if (pipe(pipefd)) {
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, pipe failed : %s", strerror(errno));
}
/* Does this preserve existing signal handlers? */
pid = fork();
@@ -221,8 +231,22 @@ go_daemon(void)
if (pid < 0) {
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
} else if (pid > 0) {
exit(0); /* In the 'grandparent' */
/* In the 'grandparent' */
char message[1024];
int r;
close(pipefd[1]);
r = read(pipefd[0], message, sizeof (message));
if (r) {
if (r > 0) {
/* Print the error message from the child */
fprintf(stderr, "%.1024s\n", message);
}
exit(1);
} else
exit(0);
} else {
close(pipefd[0]);
setsid();
@@ -236,10 +260,19 @@ go_daemon(void)
} else {
/* In the child we want to leave running as the daemon */
/* Don't keep stdin/out/err from before. */
for (fd=0; fd<1024; fd++) {
close(fd);
/* Change current directory to / */
if (chdir("/") < 0) {
LOG(LOGS_ERR, LOGF_Logging, "Could not chdir to / : %s", strerror(errno));
}
/* Don't keep stdin/out/err from before. But don't close
the parent pipe yet. */
for (fd=0; fd<1024; fd++) {
if (fd != pipefd[1])
close(fd);
}
LOG_SetParentFd(pipefd[1]);
}
}
@@ -251,10 +284,10 @@ go_daemon(void)
int main
(int argc, char **argv)
{
char *conf_file = NULL;
const char *conf_file = DEFAULT_CONF_FILE;
char *user = NULL;
int debug = 0, nofork = 0;
int do_init_rtc = 0;
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
int do_init_rtc = 0, restarted = 0;
int other_pid;
int lock_memory = 0, sched_priority = 0;
@@ -275,6 +308,8 @@ int main
lock_memory = 1;
} else if (!strcmp("-r", *argv)) {
reload = 1;
} else if (!strcmp("-R", *argv)) {
restarted = 1;
} else if (!strcmp("-u", *argv)) {
++argv, --argc;
if (argc == 0) {
@@ -286,7 +321,7 @@ int main
do_init_rtc = 1;
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
printf("chronyd (chrony) version %s\n", PROGRAM_VERSION_STRING);
printf("chronyd (chrony) version %s\n", CHRONY_VERSION);
exit(0);
} else if (!strcmp("-n", *argv)) {
nofork = 1;
@@ -294,17 +329,14 @@ int main
debug = 1;
nofork = 1;
} else if (!strcmp("-4", *argv)) {
DNS_SetAddressFamily(IPADDR_INET4);
address_family = IPADDR_INET4;
} else if (!strcmp("-6", *argv)) {
DNS_SetAddressFamily(IPADDR_INET6);
address_family = IPADDR_INET6;
} else {
LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
}
}
CNF_ReadFile(conf_file);
#ifndef SYS_WINNT
if (getuid() != 0) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
fprintf(stderr,"Not superuser\n");
@@ -320,7 +352,12 @@ int main
LOG_OpenSystemLog();
}
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting", PROGRAM_VERSION_STRING);
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting", CHRONY_VERSION);
DNS_SetAddressFamily(address_family);
CNF_SetRestarted(restarted);
CNF_ReadFile(conf_file);
/* Check whether another chronyd may already be running. Do this after
* forking, so that message logging goes to the right place (i.e. syslog), in
@@ -328,13 +365,11 @@ int main
if (maybe_another_chronyd_running(&other_pid)) {
LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
other_pid, CNF_GetPidFile());
exit(1);
}
/* Write our lockfile to prevent other chronyds running. This has *GOT* to
* be done *AFTER* the daemon-creation fork() */
write_lockfile();
#endif
if (do_init_rtc) {
RTC_TimePreInit();
@@ -343,11 +378,12 @@ int main
LCL_Initialise();
SCH_Initialise();
SYS_Initialise();
NIO_Initialise();
CAM_Initialise();
NIO_Initialise(address_family);
CAM_Initialise(address_family);
RTC_Initialise();
SRC_Initialise();
RCL_Initialise();
KEY_Initialise();
/* Command-line switch must have priority */
if (!sched_priority) {
@@ -361,23 +397,25 @@ int main
SYS_LockMemory();
}
if (!user) {
user = CNF_GetUser();
}
if (user) {
SYS_DropRoot(user);
}
LOG_CreateLogFileDir();
REF_Initialise();
SST_Initialise();
BRD_Initialise();
NCR_Initialise();
NSR_Initialise();
CLG_Initialise();
KEY_Initialise();
ACQ_Initialise();
MNL_Initialise();
TMC_Initialise();
LOG_CreateLogFileDir();
/* From now on, it is safe to do finalisation on exit */
initialised = 1;

View File

@@ -1,52 +1,54 @@
#!/usr/bin/env perl
#!/bin/sh
$tool = "chrony";
LANG=C
export LANG
$version = shift || die "Usage : $0 <version>\n";
$subdir = "${tool}-${version}";
if [ $# -ne 1 ]; then
echo "Usage : $0 <version>"
exit 2
fi
unless (-d ".git") {
die "No .git subdirectory?"
}
version=$1
subdir=chrony-${version}
mandate=$(date +'%B %Y')
unless (-d "RELEASES") {
mkdir "RELEASES", 0755;
}
umask 022
system ("git tag -s $version");
die "git-tag failed" if ($? != 0);
if (-d "RELEASES/$subdir") {
system ("rm -rf RELEASES/$subdir");
}
if [ ! -d .git ]; then
echo "No .git subdirectory?"
exit 3
fi
system ("git archive --format=tar --prefix=RELEASES/${subdir}/ $version | tar xf -");
die "git-tar-tree failed" if ($? != 0);
[ -d RELEASES ] || mkdir RELEASES
chdir "RELEASES";
$here = qx/pwd/;
chomp $here;
chdir $subdir;
git tag -s $version || exit 1
open (OUT, ">version.txt");
print OUT $version."\n";
close OUT;
rm -rf RELEASES/$subdir
open (IN, "<${tool}.spec.sample");
open (OUT, ">${tool}.spec");
while (<IN>) {
s/\@\@VERSION\@\@/$version/;
print OUT;
}
close (IN);
close (OUT);
git archive --format=tar --prefix=RELEASES/${subdir}/ $version | \
tar xf - || exit 1
system("makeinfo --no-headers --number-sections -o chrony.txt chrony.texi");
unlink "make_release";
unlink "${tool}.spec.sample";
unlink ".gitignore";
cd RELEASES/$subdir || exit 1
chdir $here;
system ("tar cvf - $subdir | gzip -9 > ${subdir}.tar.gz");
system ("gpg -b -a -o ${subdir}-tar-gz-asc.txt ${subdir}.tar.gz");
echo $version > version.txt
sed -e "s%@@VERSION@@%${version}%" < chrony.spec.sample > chrony.spec
for m in chrony.1.in chronyc.1.in chrony.conf.5.in chronyd.8.in; do
sed -e "s%@VERSION@%${version}%;s%@MAN_DATE@%${mandate}%" \
< $m > ${m}_
mv -f ${m}_ $m
done
./configure && make chrony.txt || exit 1
mv chrony.txt chrony.txt_
make distclean
mv chrony.txt_ chrony.txt
rm -f faqgen.pl make_release chrony.spec.sample .gitignore
cd ..
tar cvf - $subdir | gzip -9 > ${subdir}.tar.gz
gpg -b -a -o ${subdir}-tar-gz-asc.txt ${subdir}.tar.gz

View File

@@ -30,7 +30,9 @@
*/
#include <stddef.h>
#include "config.h"
#include "sysincl.h"
#include "manual.h"
#include "logging.h"
@@ -91,8 +93,6 @@ MNL_Initialise(void)
error = ERROR_MARGIN;
LCL_AddParameterChangeHandler(slew_samples, NULL);
return;
}
/* ================================================== */
@@ -100,7 +100,6 @@ MNL_Initialise(void)
void
MNL_Finalise(void)
{
return;
}
/* ================================================== */
@@ -143,6 +142,8 @@ estimate_and_set_system(struct timeval *now, int offset_provided, double offset,
}
b1 = freq = 0.0;
found_freq = 0;
agos[0] = 0.0;
offsets[0] = b0;
}
if (offset_provided) {
@@ -153,7 +154,7 @@ estimate_and_set_system(struct timeval *now, int offset_provided, double offset,
if (found_freq) {
LOG(LOGS_INFO, LOGF_Manual,
"Making a frequency change of %.3fppm and a slew of %.6f\n",
"Making a frequency change of %.3f ppm and a slew of %.6f",
1.0e6 * freq, slew_by);
REF_SetManualReference(now,
@@ -235,7 +236,6 @@ slew_samples(struct timeval *raw,
dfreq, doffset);
samples[i].offset += delta_time;
}
return;
}
/* ================================================== */

6
md5.h
View File

@@ -32,11 +32,7 @@
***********************************************************************
*/
#ifdef HAS_STDINT_H
#include <stdint.h>
#elif defined(HAS_INTTYPES_H)
#include <inttypes.h>
#endif
#include "sysincl.h"
/* typedef a 32-bit type */
typedef uint32_t UINT4;

View File

@@ -27,8 +27,6 @@
#ifndef GOT_MEMORY_H
#define GOT_MEMORY_H
#include <stdlib.h>
#define Malloc(x) malloc(x)
#define MallocNew(T) ((T *) malloc(sizeof(T)))
#define MallocArray(T, n) ((T *) malloc((n) * sizeof(T)))

View File

@@ -26,6 +26,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "mkdirpp.h"

View File

@@ -1,15 +0,0 @@
#!/bin/sh
rm -f version.h
echo "#ifndef VERSION_H" > version.h
echo "#define VERSION_H 1" >> version.h
if [ -f version.txt ]; then
ver=`cat version.txt`
echo "#define PROGRAM_VERSION_STRING \"$ver\"" >> version.h
else
echo "#define PROGRAM_VERSION_STRING \"DEVELOPMENT\"" >> version.h
fi
echo "#endif /* VERSION_H */" >> version.h

View File

@@ -26,11 +26,12 @@
*/
#include "config.h"
#include "sysincl.h"
#include "nameserv.h"
#include "util.h"
#include <resolv.h>
/* ================================================== */

32
ntp.h
View File

@@ -27,11 +27,9 @@
#ifndef GOT_NTP_H
#define GOT_NTP_H
#ifdef HAS_STDINT_H
#include <stdint.h>
#elif defined(HAS_INTTYPES_H)
#include <inttypes.h>
#endif
#include "sysincl.h"
#include "hash.h"
typedef struct {
uint32_t hi;
@@ -40,7 +38,7 @@ typedef struct {
typedef uint32_t NTP_int32;
#define AUTH_DATA_LEN 16
#define MAX_NTP_AUTH_DATA_LEN MAX_HASH_LENGTH
/* Type definition for leap bits */
typedef enum {
@@ -72,7 +70,7 @@ typedef struct {
NTP_int64 receive_ts;
NTP_int64 transmit_ts;
NTP_int32 auth_keyid;
uint8_t auth_data[AUTH_DATA_LEN];
uint8_t auth_data[MAX_NTP_AUTH_DATA_LEN];
} NTP_Packet;
/* We have to declare a buffer type to hold a datagram read from the
@@ -89,24 +87,6 @@ typedef union {
uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
} ReceiveBuffer;
#define NTP_NORMAL_PACKET_SIZE (sizeof(NTP_Packet) - (sizeof(NTP_int32) + AUTH_DATA_LEN))
/* ================================================== */
inline static double
int32_to_double(NTP_int32 x)
{
return (double) ntohl(x) / 65536.0;
}
/* ================================================== */
inline static NTP_int32
double_to_int32(double x)
{
return htonl((NTP_int32)(0.5 + 65536.0 * x));
}
/* ================================================== */
#define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
#endif /* GOT_NTP_H */

File diff suppressed because it is too large Load Diff

View File

@@ -54,20 +54,11 @@ extern void NCR_DestroyInstance(NCR_Instance instance);
/* This routine is called when a new packet arrives off the network,
and it relates to a source we have an ongoing protocol exchange with */
extern void NCR_ProcessNoauthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data);
extern void NCR_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, int length);
/* This routine is called when a new packet arrives off the network,
and we do not recognize its source */
extern void NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
/* This routine is called when a new authenticated packet arrives off
the network, and it relates to a source we have an ongoing protocol
exchange with */
extern void NCR_ProcessAuthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data);
/* This routine is called when a new authenticated packet arrives off
the network, and we do not recognize its source */
extern void NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
extern void NCR_ProcessUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length);
/* Slew receive and transmit times in instance records */
extern void NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset);

View File

@@ -26,6 +26,8 @@
This file deals with the IO aspects of reading and writing NTP packets
*/
#include "config.h"
#include "sysincl.h"
#include "ntp_io.h"
@@ -37,8 +39,6 @@
#include "conf.h"
#include "util.h"
#include <fcntl.h>
union sockaddr_in46 {
struct sockaddr_in in4;
#ifdef HAVE_IPV6
@@ -157,6 +157,16 @@ prepare_socket(int family)
LOG(LOGS_ERR, LOGF_NtpIO, "Could not request IPV6_V6ONLY socket option");
}
#endif
#ifdef IPV6_RECVPKTINFO
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not request IPv6 packet info socket option");
}
#elif defined(IPV6_PKTINFO)
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not request IPv6 packet info socket option");
}
#endif
}
#endif
@@ -200,8 +210,10 @@ prepare_socket(int family)
#endif
if (bind(sock_fd, &my_addr.u, my_addr_len) < 0) {
LOG_FATAL(LOGF_NtpIO, "Could not bind %s NTP socket : %s",
LOG(LOGS_ERR, LOGF_NtpIO, "Could not bind %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
close(sock_fd);
return -1;
}
/* Register handler for read events on the socket */
@@ -219,17 +231,25 @@ prepare_socket(int family)
return sock_fd;
}
/* ================================================== */
void
NIO_Initialise(void)
NIO_Initialise(int family)
{
assert(!initialised);
initialised = 1;
do_size_checks();
sock_fd4 = prepare_socket(AF_INET);
if (family == IPADDR_UNSPEC || family == IPADDR_INET4)
sock_fd4 = prepare_socket(AF_INET);
else
sock_fd4 = -1;
#ifdef HAVE_IPV6
sock_fd6 = prepare_socket(AF_INET6);
if (family == IPADDR_UNSPEC || family == IPADDR_INET6)
sock_fd6 = prepare_socket(AF_INET6);
else
sock_fd6 = -1;
#endif
if (sock_fd4 < 0
@@ -239,8 +259,6 @@ NIO_Initialise(void)
) {
LOG_FATAL(LOGF_NtpIO, "Could not open any NTP socket");
}
return;
}
/* ================================================== */
@@ -261,7 +279,6 @@ NIO_Finalise(void)
sock_fd6 = -1;
#endif
initialised = 0;
return;
}
/* ================================================== */
@@ -279,7 +296,7 @@ read_from_socket(void *anything)
ReceiveBuffer message;
union sockaddr_in46 where_from;
unsigned int flags = 0;
struct timeval now;
struct timeval now, now_raw;
double now_err;
NTP_Remote_Address remote_addr;
char cmsgbuf[256];
@@ -289,7 +306,7 @@ read_from_socket(void *anything)
assert(initialised);
SCH_GetFileReadyTime(&now, &now_err);
SCH_GetLastEventTime(&now, &now_err, &now_raw);
iov.iov_base = message.arbitrary;
iov.iov_len = sizeof(message);
@@ -343,23 +360,32 @@ read_from_socket(void *anything)
}
#endif
#if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
struct in6_pktinfo ipi;
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
memcpy(&remote_addr.local_ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
sizeof (remote_addr.local_ip_addr.addr.in6));
remote_addr.local_ip_addr.family = IPADDR_INET6;
}
#endif
#ifdef SO_TIMESTAMP
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP) {
struct timeval tv;
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
LCL_CookTime(&tv, &now, &now_err);
/* This should be more accurate than LCL_CookTime(&now_raw,...) */
UTI_AddDiffToTimeval(&now, &now_raw, &tv, &now);
}
#endif
}
if (status == NTP_NORMAL_PACKET_SIZE) {
if (status >= NTP_NORMAL_PACKET_SIZE && status <= sizeof(NTP_Packet)) {
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr);
} else if (status == sizeof(NTP_Packet)) {
NSR_ProcessAuthenticatedReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr);
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr, status);
} else {
@@ -367,8 +393,6 @@ read_from_socket(void *anything)
}
}
return;
}
/* ================================================== */
@@ -443,6 +467,25 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr)
}
#endif
#if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
if (remote_addr->local_ip_addr.family == IPADDR_INET6) {
struct cmsghdr *cmsg;
struct in6_pktinfo *ipi;
cmsg = CMSG_FIRSTHDR(&msg);
memset(cmsg, 0, CMSG_SPACE(sizeof(struct in6_pktinfo)));
cmsglen += CMSG_SPACE(sizeof(struct in6_pktinfo));
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
ipi = (struct in6_pktinfo *) CMSG_DATA(cmsg);
memcpy(&ipi->ipi6_addr.s6_addr, &remote_addr->local_ip_addr.addr.in6,
sizeof(ipi->ipi6_addr.s6_addr));
}
#endif
#if 0
LOG(LOGS_INFO, LOGF_NtpIO, "sending to %s:%d from %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, UTI_IPToString(&remote_addr->local_ip_addr));
@@ -464,8 +507,6 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr)
LOG(LOGS_WARN, LOGF_NtpIO, "Could not send to %s:%d : %s",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, strerror(errno));
}
return;
}
/* ================================================== */
@@ -481,9 +522,9 @@ NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr)
/* Send an authenticated packet to a given address */
void
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr)
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, int auth_len)
{
send_packet((void *) packet, sizeof(NTP_Packet), remote_addr);
send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE + auth_len, remote_addr);
}
/* ================================================== */

View File

@@ -32,7 +32,7 @@
#include "addressing.h"
/* Function to initialise the module. */
extern void NIO_Initialise(void);
extern void NIO_Initialise(int family);
/* Function to finalise the module */
extern void NIO_Finalise(void);
@@ -41,7 +41,7 @@ extern void NIO_Finalise(void);
extern void NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr);
/* Function to transmit an authenticated packet */
extern void NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr);
extern void NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, int auth_len);
/* Function to send a datagram to a remote machine's UDP echo port. */
extern void NIO_SendEcho(NTP_Remote_Address *remote_addr);

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
* Copyright (C) Miroslav Lichvar 2011-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -27,6 +27,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "ntp_sources.h"
@@ -101,8 +103,6 @@ NSR_Initialise(void)
initialised = 1;
LCL_AddParameterChangeHandler(slew_sources, NULL);
return;
}
/* ================================================== */
@@ -111,7 +111,6 @@ void
NSR_Finalise(void)
{
initialised = 0;
return; /* Nothing to do yet */
}
/* ================================================== */
@@ -177,8 +176,6 @@ find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
*found = 0;
*slot = hash;
}
return;
}
/* ================================================== */
@@ -285,6 +282,19 @@ NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParame
/* ================================================== */
void
NSR_ResolveSources(void)
{
/* Try to resolve unresolved sources now */
if (resolving_interval) {
SCH_RemoveTimeout(resolving_id);
resolving_interval--;
resolve_sources(NULL);
}
}
/* ================================================== */
/* Procedure to remove a source. We don't bother whether the port
address is matched - we're only interested in removing a record for
the right IP address. Thus the caller can specify the port number
@@ -331,9 +341,10 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr)
/* ================================================== */
/* This routine is called by ntp_io when a new packet arrives off the network.*/
/* This routine is called by ntp_io when a new packet arrives off the network,
possibly with an authentication tail */
void
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length)
{
int slot, found;
@@ -347,27 +358,9 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP
find_slot(remote_addr, &slot, &found);
if (found == 2) { /* Must match IP address AND port number */
NCR_ProcessNoauthKnown(message, now, now_err, records[slot].data);
NCR_ProcessKnown(message, now, now_err, records[slot].data, length);
} else {
NCR_ProcessNoauthUnknown(message, now, now_err, remote_addr);
}
}
/* ================================================== */
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
void
NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
int slot, found;
assert(initialised);
find_slot(remote_addr, &slot, &found);
if (found == 2) {
NCR_ProcessAuthKnown(message, now, now_err, records[slot].data);
} else {
NCR_ProcessAuthUnknown(message, now, now_err, remote_addr);
NCR_ProcessUnknown(message, now, now_err, remote_addr, length);
}
}
@@ -404,12 +397,7 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
int i;
int any;
/* Try to resolve unresolved sources now */
if (resolving_interval) {
SCH_RemoveTimeout(resolving_id);
resolving_interval--;
resolve_sources(NULL);
}
NSR_ResolveSources();
any = 0;
for (i=0; i<N_RECORDS; i++) {
@@ -672,12 +660,11 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
}
}
/* Add unresolved sources to offline count */
for (us = unresolved_sources; us; us = us->next) {
report->offline++;
}
report->unresolved = 0;
return;
for (us = unresolved_sources; us; us = us->next) {
report->unresolved++;
}
}

View File

@@ -54,14 +54,14 @@ extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type
until it succeeds or fails with a non-temporary error. */
extern void NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params);
/* Procedure to try resolve unresolved sources immediately. */
extern void NSR_ResolveSources(void);
/* Procedure to remove a source */
extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
/* This routine is called by ntp_io when a new packet arrives off the network */
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
extern void NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length);
/* Initialisation function */
extern void NSR_Initialise(void);

View File

@@ -26,6 +26,8 @@
integer endianness within the structures.
*/
#include "config.h"
#include "sysincl.h"
#include "util.h"
@@ -33,8 +35,8 @@
/* ================================================== */
int
PKL_CommandLength(CMD_Request *r)
static int
command_unpadded_length(CMD_Request *r)
{
int type;
type = ntohs(r->command);
@@ -122,19 +124,9 @@ PKL_CommandLength(CMD_Request *r)
case REQ_CYCLELOGS :
return offsetof(CMD_Request, data.cyclelogs.EOR);
case REQ_SUBNETS_ACCESSED :
{
unsigned long ns;
ns = ntohl(r->data.subnets_accessed.n_subnets);
return (offsetof(CMD_Request, data.subnets_accessed.subnets) +
ns * sizeof(REQ_SubnetsAccessed_Subnet));
}
case REQ_CLIENT_ACCESSES:
{
unsigned long nc;
nc = ntohl(r->data.client_accesses.n_clients);
return (offsetof(CMD_Request, data.client_accesses.client_ips) +
nc * sizeof(unsigned long));
}
/* No longer supported */
return 0;
case REQ_CLIENT_ACCESSES_BY_INDEX:
return offsetof(CMD_Request, data.client_accesses_by_index.EOR);
case REQ_MANUAL_LIST:
@@ -165,6 +157,149 @@ PKL_CommandLength(CMD_Request *r)
}
/* ================================================== */
int
PKL_CommandLength(CMD_Request *r)
{
int command_length;
command_length = command_unpadded_length(r);
if (!command_length)
return 0;
return command_length + PKL_CommandPaddingLength(r);
}
/* ================================================== */
#define PADDING_LENGTH_(request_length, reply_length) \
((request_length) < (reply_length) ? (reply_length) - (request_length) : 0)
#define PADDING_LENGTH(request_data, reply_data) \
PADDING_LENGTH_(offsetof(CMD_Request, request_data), offsetof(CMD_Reply, reply_data))
int
PKL_CommandPaddingLength(CMD_Request *r)
{
int type;
if (r->version < PROTO_VERSION_PADDING)
return 0;
type = ntohs(r->command);
if (type < 0 || type >= N_REQUEST_TYPES)
return 0;
switch (type) {
case REQ_NULL:
return PADDING_LENGTH(data, data.null.EOR);
case REQ_ONLINE:
return PADDING_LENGTH(data.online.EOR, data.null.EOR);
case REQ_OFFLINE:
return PADDING_LENGTH(data.offline.EOR, data.null.EOR);
case REQ_BURST:
return PADDING_LENGTH(data.burst.EOR, data.null.EOR);
case REQ_MODIFY_MINPOLL:
return PADDING_LENGTH(data.modify_minpoll.EOR, data.null.EOR);
case REQ_MODIFY_MAXPOLL:
return PADDING_LENGTH(data.modify_maxpoll.EOR, data.null.EOR);
case REQ_DUMP:
return PADDING_LENGTH(data.dump.EOR, data.null.EOR);
case REQ_MODIFY_MAXDELAY:
return PADDING_LENGTH(data.modify_maxdelay.EOR, data.null.EOR);
case REQ_MODIFY_MAXDELAYRATIO:
return PADDING_LENGTH(data.modify_maxdelayratio.EOR, data.null.EOR);
case REQ_MODIFY_MAXDELAYDEVRATIO:
return PADDING_LENGTH(data.modify_maxdelaydevratio.EOR, data.null.EOR);
case REQ_MODIFY_MAXUPDATESKEW:
return PADDING_LENGTH(data.modify_maxupdateskew.EOR, data.null.EOR);
case REQ_LOGON:
return PADDING_LENGTH(data.logon.EOR, data.null.EOR);
case REQ_SETTIME:
return PADDING_LENGTH(data.settime.EOR, data.manual_timestamp.EOR);
case REQ_LOCAL:
return PADDING_LENGTH(data.local.EOR, data.null.EOR);
case REQ_MANUAL:
return PADDING_LENGTH(data.manual.EOR, data.null.EOR);
case REQ_N_SOURCES:
return PADDING_LENGTH(data.n_sources.EOR, data.n_sources.EOR);
case REQ_SOURCE_DATA:
return PADDING_LENGTH(data.source_data.EOR, data.source_data.EOR);
case REQ_REKEY:
return PADDING_LENGTH(data.rekey.EOR, data.null.EOR);
case REQ_ALLOW:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_ALLOWALL:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_DENY:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_DENYALL:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_CMDALLOW:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_CMDALLOWALL:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_CMDDENY:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_CMDDENYALL:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_ACCHECK:
return PADDING_LENGTH(data.ac_check.EOR, data.null.EOR);
case REQ_CMDACCHECK:
return PADDING_LENGTH(data.ac_check.EOR, data.null.EOR);
case REQ_ADD_SERVER:
return PADDING_LENGTH(data.ntp_source.EOR, data.null.EOR);
case REQ_ADD_PEER:
return PADDING_LENGTH(data.ntp_source.EOR, data.null.EOR);
case REQ_DEL_SOURCE:
return PADDING_LENGTH(data.del_source.EOR, data.null.EOR);
case REQ_WRITERTC:
return PADDING_LENGTH(data.writertc.EOR, data.null.EOR);
case REQ_DFREQ:
return PADDING_LENGTH(data.dfreq.EOR, data.null.EOR);
case REQ_DOFFSET:
return PADDING_LENGTH(data.doffset.EOR, data.null.EOR);
case REQ_TRACKING:
return PADDING_LENGTH(data.tracking.EOR, data.tracking.EOR);
case REQ_SOURCESTATS:
return PADDING_LENGTH(data.sourcestats.EOR, data.sourcestats.EOR);
case REQ_RTCREPORT:
return PADDING_LENGTH(data.rtcreport.EOR, data.rtc.EOR);
case REQ_TRIMRTC:
return PADDING_LENGTH(data.trimrtc.EOR, data.null.EOR);
case REQ_CYCLELOGS:
return PADDING_LENGTH(data.cyclelogs.EOR, data.null.EOR);
case REQ_SUBNETS_ACCESSED:
case REQ_CLIENT_ACCESSES:
/* No longer supported */
return 0;
case REQ_CLIENT_ACCESSES_BY_INDEX:
return PADDING_LENGTH(data.client_accesses_by_index.EOR, data.client_accesses_by_index.EOR);
case REQ_MANUAL_LIST:
return PADDING_LENGTH(data.manual_list.EOR, data.manual_list.EOR);
case REQ_MANUAL_DELETE:
return PADDING_LENGTH(data.manual_delete.EOR, data.null.EOR);
case REQ_MAKESTEP:
return PADDING_LENGTH(data.make_step.EOR, data.null.EOR);
case REQ_ACTIVITY:
return PADDING_LENGTH(data.activity.EOR, data.activity.EOR);
case REQ_RESELECT:
return PADDING_LENGTH(data.reselect.EOR, data.null.EOR);
case REQ_RESELECTDISTANCE:
return PADDING_LENGTH(data.reselect_distance.EOR, data.null.EOR);
case REQ_MODIFY_MINSTRATUM:
return PADDING_LENGTH(data.modify_minstratum.EOR, data.null.EOR);
case REQ_MODIFY_POLLTARGET:
return PADDING_LENGTH(data.modify_polltarget.EOR, data.null.EOR);
default:
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
assert(0);
return 0;
}
}
/* ================================================== */
int
@@ -192,29 +327,15 @@ PKL_ReplyLength(CMD_Reply *r)
case RPY_RTC:
return offsetof(CMD_Reply, data.rtc.EOR);
case RPY_SUBNETS_ACCESSED :
{
unsigned long ns = ntohl(r->data.subnets_accessed.n_subnets);
if (r->status == htons(STT_SUCCESS)) {
return (offsetof(CMD_Reply, data.subnets_accessed.subnets) +
ns * sizeof(RPY_SubnetsAccessed_Subnet));
} else {
return offsetof(CMD_Reply, data);
}
}
case RPY_CLIENT_ACCESSES:
{
unsigned long nc = ntohl(r->data.client_accesses.n_clients);
if (r->status == htons(STT_SUCCESS)) {
return (offsetof(CMD_Reply, data.client_accesses.clients) +
nc * sizeof(RPY_ClientAccesses_Client));
} else {
return offsetof(CMD_Reply, data);
}
}
/* No longer supported */
return 0;
case RPY_CLIENT_ACCESSES_BY_INDEX:
{
unsigned long nc = ntohl(r->data.client_accesses_by_index.n_clients);
if (r->status == htons(STT_SUCCESS)) {
if (nc > MAX_CLIENT_ACCESSES)
return 0;
return (offsetof(CMD_Reply, data.client_accesses_by_index.clients) +
nc * sizeof(RPY_ClientAccesses_Client));
} else {
@@ -224,6 +345,8 @@ PKL_ReplyLength(CMD_Reply *r)
case RPY_MANUAL_LIST:
{
unsigned long ns = ntohl(r->data.manual_list.n_samples);
if (ns > MAX_MANUAL_LIST_SAMPLES)
return 0;
if (r->status == htons(STT_SUCCESS)) {
return (offsetof(CMD_Reply, data.manual_list.samples) +
ns * sizeof(RPY_ManualListSample));

View File

@@ -33,6 +33,8 @@
extern int PKL_CommandLength(CMD_Request *r);
extern int PKL_CommandPaddingLength(CMD_Request *r);
extern int PKL_ReplyLength(CMD_Reply *r);
#endif /* GOT_PKTLENGTH_H */

View File

@@ -25,6 +25,8 @@
*/
#include "config.h"
#include "refclock.h"
#include "reference.h"
#include "conf.h"
@@ -72,8 +74,8 @@ struct RCL_Instance_Record {
int leap_status;
int pps_rate;
struct MedianFilter filter;
unsigned long ref_id;
unsigned long lock_ref;
uint32_t ref_id;
uint32_t lock_ref;
double offset;
double delay;
double precision;
@@ -112,6 +114,11 @@ RCL_Initialise(void)
{
CNF_AddRefclocks();
if (n_sources > 0) {
LCL_AddParameterChangeHandler(slew_samples, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
}
logfileid = CNF_GetLogRefclocks() ? LOG_FileOpen("refclocks",
" Date (UTC) Time Refid DP L P Raw offset Cooked offset Disp.")
: -1;
@@ -148,14 +155,14 @@ RCL_AddRefclock(RefclockParameters *params)
if (n_sources == MAX_RCL_SOURCES)
return 0;
if (strncmp(params->driver_name, "SHM", 4) == 0) {
if (strcmp(params->driver_name, "SHM") == 0) {
inst->driver = &RCL_SHM_driver;
inst->precision = 1e-6;
} else if (strncmp(params->driver_name, "SOCK", 4) == 0) {
} else if (strcmp(params->driver_name, "SOCK") == 0) {
inst->driver = &RCL_SOCK_driver;
inst->precision = 1e-9;
pps_source = 1;
} else if (strncmp(params->driver_name, "PPS", 4) == 0) {
} else if (strcmp(params->driver_name, "PPS") == 0) {
inst->driver = &RCL_PPS_driver;
inst->precision = 1e-9;
pps_source = 1;
@@ -175,7 +182,7 @@ RCL_AddRefclock(RefclockParameters *params)
inst->driver_poll = params->driver_poll;
inst->poll = params->poll;
inst->driver_polled = 0;
inst->leap_status = 0;
inst->leap_status = LEAP_Normal;
inst->pps_rate = params->pps_rate;
inst->lock_ref = params->lock_ref_id;
inst->offset = params->offset;
@@ -242,6 +249,8 @@ RCL_AddRefclock(RefclockParameters *params)
#endif
n_sources++;
Free(params->driver_name);
return 1;
}
@@ -264,18 +273,13 @@ RCL_StartRefclocks(void)
} else
inst->lock_ref = -1;
}
if (n_sources > 0) {
LCL_AddParameterChangeHandler(slew_samples, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
}
}
void
RCL_ReportSource(RPT_SourceReport *report, struct timeval *now)
{
int i;
unsigned long ref_id;
uint32_t ref_id;
assert(report->ip_addr.family == IPADDR_INET4);
ref_id = report->ip_addr.addr.in4;
@@ -334,7 +338,7 @@ RCL_GetDriverOption(RCL_Instance instance, char *name)
}
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, int leap)
{
double correction, dispersion;
struct timeval cooked_time;
@@ -347,7 +351,17 @@ RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset,
return 0;
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset, dispersion);
instance->leap_status = leap_status;
switch (leap) {
case LEAP_Normal:
case LEAP_InsertSecond:
case LEAP_DeleteSecond:
instance->leap_status = leap;
break;
default:
instance->leap_status = LEAP_Unsynchronised;
break;
}
log_sample(instance, &cooked_time, 0, 0, offset, offset - correction + instance->offset, dispersion);
@@ -416,7 +430,7 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
int is_synchronised, stratum;
double root_delay, root_dispersion, distance;
NTP_Leap leap;
unsigned long ref_id;
uint32_t ref_id;
/* Ignore the pulse if we are not well synchronized */
@@ -438,7 +452,7 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
filter_add_sample(&instance->filter, &cooked_time, offset, dispersion);
instance->leap_status = LEAP_Normal;
log_sample(instance, &cooked_time, 0, 1, second, offset, dispersion);
log_sample(instance, &cooked_time, 0, 1, offset + correction - instance->offset, offset, dispersion);
/* for logging purposes */
if (!instance->driver->poll)
@@ -467,7 +481,7 @@ pps_stratum(RCL_Instance instance, struct timeval *tv)
int is_synchronised, stratum, i;
double root_delay, root_dispersion;
NTP_Leap leap;
unsigned long ref_id;
uint32_t ref_id;
REF_GetReferenceParams(tv, &is_synchronised, &leap, &stratum,
&ref_id, &ref_time, &root_delay, &root_dispersion);

View File

@@ -32,14 +32,14 @@
#include "sources.h"
typedef struct {
char driver_name[4];
char *driver_name;
char *driver_parameter;
int driver_poll;
int poll;
int filter_length;
int pps_rate;
unsigned long ref_id;
unsigned long lock_ref_id;
uint32_t ref_id;
uint32_t lock_ref_id;
double offset;
double delay;
double precision;
@@ -66,7 +66,7 @@ extern void RCL_SetDriverData(RCL_Instance instance, void *data);
extern void *RCL_GetDriverData(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, int leap);
extern int RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second);
#endif

View File

@@ -25,11 +25,17 @@
*/
#include "config.h"
#include "refclock.h"
#if HAVE_PPSAPI
#if defined(HAVE_SYS_TIMEPPS_H)
#include <sys/timepps.h>
#elif defined(HAVE_TIMEPPS_H)
#include <timepps.h>
#endif
#include "logging.h"
#include "memory.h"

View File

@@ -25,13 +25,14 @@
*/
#include "config.h"
#include "sysincl.h"
#include "refclock.h"
#include "logging.h"
#include "util.h"
#include <sys/types.h>
#include <sys/shm.h>
#define SHMKEY 0x4e545030
struct shmTime {
@@ -43,7 +44,7 @@ struct shmTime {
* use values
* clear valid
*/
int count;
volatile int count;
time_t clockTimeStampSec;
int clockTimeStampUSec;
time_t receiveTimeStampSec;
@@ -51,8 +52,10 @@ struct shmTime {
int leap;
int precision;
int nsamples;
int valid;
int dummy[10];
volatile int valid;
int clockTimeStampNSec;
int receiveTimeStampNSec;
int dummy[8];
};
static int shm_initialise(RCL_Instance instance) {
@@ -87,7 +90,7 @@ static void shm_finalise(RCL_Instance instance)
static int shm_poll(RCL_Instance instance)
{
struct timeval tv1, tv2;
struct timeval tv;
struct shmTime t, *shm;
double offset;
@@ -105,13 +108,17 @@ static int shm_poll(RCL_Instance instance)
shm->valid = 0;
tv1.tv_sec = t.receiveTimeStampSec;
tv1.tv_usec = t.receiveTimeStampUSec;
tv2.tv_sec = t.clockTimeStampSec;
tv2.tv_usec = t.clockTimeStampUSec;
tv.tv_sec = t.receiveTimeStampSec;
tv.tv_usec = t.receiveTimeStampUSec;
UTI_DiffTimevalsToDouble(&offset, &tv2, &tv1);
return RCL_AddSample(instance, &tv1, offset, t.leap);
offset = t.clockTimeStampSec - t.receiveTimeStampSec;
if (t.clockTimeStampNSec / 1000 == t.clockTimeStampUSec &&
t.receiveTimeStampNSec / 1000 == t.receiveTimeStampUSec)
offset += (t.clockTimeStampNSec - t.receiveTimeStampNSec) * 1e-9;
else
offset += (t.clockTimeStampUSec - t.receiveTimeStampUSec) * 1e-6;
return RCL_AddSample(instance, &tv, offset, t.leap);
}
RefclockDriver RCL_SHM_driver = {

View File

@@ -25,16 +25,15 @@
*/
#include "config.h"
#include "sysincl.h"
#include "refclock.h"
#include "logging.h"
#include "util.h"
#include "sched.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define SOCK_MAGIC 0x534f434b
struct sock_sample {

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011
* Copyright (C) Miroslav Lichvar 2009-2013
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,6 +25,8 @@
This module keeps track of the source which we are claiming to be
our reference, for the purposes of generating outgoing NTP packets */
#include "config.h"
#include "sysincl.h"
#include "memory.h"
@@ -37,16 +39,18 @@
/* ================================================== */
/* The minimum allowed skew */
#define MIN_SKEW 1.0e-12
static int are_we_synchronised;
static int enable_local_stratum;
static int local_stratum;
static NTP_Leap our_leap_status;
static int our_leap_sec;
static int our_stratum;
static unsigned long our_ref_id;
static uint32_t our_ref_id;
static IPAddr our_ref_ip;
struct timeval our_ref_time; /* Stored relative to reference, NOT local time */
static double our_offset;
static double our_skew;
static double our_residual_freq;
static double our_root_delay;
@@ -54,6 +58,12 @@ static double our_root_dispersion;
static double max_update_skew;
static double last_offset;
static double avg2_offset;
static int avg2_moving;
static double correction_time_ratio;
/* Flag indicating that we are initialised */
static int initialised = 0;
@@ -61,6 +71,12 @@ static int initialised = 0;
static int make_step_limit;
static double make_step_threshold;
/* Number of updates before offset checking, number of ignored updates
before exiting and the maximum allowed offset */
static int max_offset_delay;
static int max_offset_ignore;
static double max_offset;
/* Flag and threshold for logging clock changes to syslog */
static int do_log_change;
static double log_change_threshold;
@@ -76,7 +92,10 @@ static double drift_file_age;
static void update_drift_file(double, double);
#define MAIL_PROGRAM "/usr/lib/sendmail"
/* Name of a system timezone containing leap seconds occuring at midnight */
static char *leap_tzname;
static time_t last_tz_leap_check;
static NTP_Leap tz_leap;
/* ================================================== */
@@ -110,11 +129,29 @@ static double last_ref_update_interval;
/* ================================================== */
static NTP_Leap get_tz_leap(time_t when);
/* ================================================== */
static void
handle_slew(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double doffset,
int is_step_change,
void *anything)
{
if (is_step_change) {
UTI_AddDoubleToTimeval(&last_ref_update, -doffset, &last_ref_update);
}
}
/* ================================================== */
void
REF_Initialise(void)
{
FILE *in;
char line[1024];
double file_freq_ppm, file_skew_ppm;
double our_frequency_ppm;
@@ -127,43 +164,61 @@ REF_Initialise(void)
our_frequency_ppm = 0.0;
our_skew = 1.0; /* i.e. rather bad */
our_residual_freq = 0.0;
drift_file_age = 0.0;
/* Now see if we can get the drift file opened */
drift_file = CNF_GetDriftFile();
if (drift_file) {
in = fopen(drift_file, "r");
if (in) {
if (fgets(line, sizeof(line), in)) {
if (sscanf(line, "%lf%lf", &file_freq_ppm, &file_skew_ppm) == 2) {
/* We have read valid data */
our_frequency_ppm = file_freq_ppm;
our_skew = 1.0e-6 * file_skew_ppm;
LOG(LOGS_INFO, LOGF_Reference, "Frequency %.3f +- %.3f ppm read from %s", file_freq_ppm, file_skew_ppm, drift_file);
} else {
LOG(LOGS_WARN, LOGF_Reference, "Could not parse valid frequency and skew from driftfile %s",
drift_file);
}
if (fscanf(in, "%lf%lf", &file_freq_ppm, &file_skew_ppm) == 2) {
/* We have read valid data */
our_frequency_ppm = file_freq_ppm;
our_skew = 1.0e-6 * file_skew_ppm;
if (our_skew < MIN_SKEW)
our_skew = MIN_SKEW;
LOG(LOGS_INFO, LOGF_Reference, "Frequency %.3f +/- %.3f ppm read from %s",
file_freq_ppm, file_skew_ppm, drift_file);
LCL_SetAbsoluteFrequency(our_frequency_ppm);
} else {
LOG(LOGS_WARN, LOGF_Reference, "Could not read valid frequency and skew from driftfile %s",
drift_file);
}
fclose(in);
}
drift_file_age = 0.0;
}
LCL_SetAbsoluteFrequency(our_frequency_ppm);
if (our_frequency_ppm == 0.0) {
our_frequency_ppm = LCL_ReadAbsoluteFrequency();
if (our_frequency_ppm != 0.0) {
LOG(LOGS_INFO, LOGF_Reference, "Initial frequency %.3f ppm", our_frequency_ppm);
}
}
logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking",
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset")
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset L Co Offset sd Rem. corr.")
: -1;
max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
correction_time_ratio = CNF_GetCorrectionTimeRatio();
enable_local_stratum = CNF_AllowLocalReference(&local_stratum);
leap_tzname = CNF_GetLeapSecTimezone();
if (leap_tzname) {
/* Check that the timezone has good data for Jun 30 2008 and Dec 31 2008 */
if (get_tz_leap(1214784000) == LEAP_Normal &&
get_tz_leap(1230681600) == LEAP_InsertSecond) {
LOG(LOGS_INFO, LOGF_Reference, "Using %s timezone to obtain leap second data", leap_tzname);
} else {
LOG(LOGS_WARN, LOGF_Reference, "Timezone %s failed leap second check, ignoring", leap_tzname);
leap_tzname = NULL;
}
}
CNF_GetMakeStep(&make_step_limit, &make_step_threshold);
CNF_GetMaxChange(&max_offset_delay, &max_offset_ignore, &max_offset);
CNF_GetLogChange(&do_log_change, &log_change_threshold);
CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user);
@@ -174,11 +229,14 @@ REF_Initialise(void)
memset(fb_drifts, 0, sizeof (struct fb_drift) * (fb_drift_max - fb_drift_min + 1));
next_fb_drift = 0;
fb_drift_timeout_id = -1;
last_ref_update.tv_sec = 0;
last_ref_update.tv_usec = 0;
last_ref_update_interval = 0;
}
last_ref_update.tv_sec = 0;
last_ref_update.tv_usec = 0;
last_ref_update_interval = 0.0;
LCL_AddParameterChangeHandler(handle_slew, NULL);
/* And just to prevent anything wierd ... */
if (do_log_change) {
log_change_threshold = fabs(log_change_threshold);
@@ -186,8 +244,6 @@ REF_Initialise(void)
/* Make first entry in tracking log */
REF_SetUnsynchronised();
return;
}
/* ================================================== */
@@ -206,7 +262,6 @@ REF_Finalise(void)
Free(fb_drifts);
initialised = 0;
return;
}
/* ================================================== */
@@ -256,9 +311,13 @@ update_drift_file(double freq_ppm, double skew)
}
/* Write the frequency and skew parameters in ppm */
fprintf(out, "%20.4f %20.4f\n", freq_ppm, 1.0e6 * skew);
fclose(out);
if ((fprintf(out, "%20.6f %20.6f\n", freq_ppm, 1.0e6 * skew) < 0) |
fclose(out)) {
Free(temp_drift_file);
LOG(LOGS_WARN, LOGF_Reference, "Could not write to temporary driftfile %s.tmp",
drift_file);
return;
}
/* Clone the file attributes from the existing file if there is one. */
@@ -274,7 +333,7 @@ update_drift_file(double freq_ppm, double skew)
if (rename(temp_drift_file,drift_file)) {
unlink(temp_drift_file);
Free(temp_drift_file);
LOG(LOGS_WARN, LOGF_Reference, "Could not replace old driftfile %s with new one %s.tmp (%d)",
LOG(LOGS_WARN, LOGF_Reference, "Could not replace old driftfile %s with new one %s.tmp",
drift_file,drift_file);
return;
}
@@ -399,12 +458,11 @@ schedule_fb_drift(struct timeval *now)
#define S_MAX_USER_LEN "128"
static void
maybe_log_offset(double offset)
maybe_log_offset(double offset, time_t now)
{
double abs_offset;
FILE *p;
char buffer[BUFLEN], host[BUFLEN];
time_t now;
struct tm stm;
abs_offset = fabs(offset);
@@ -426,7 +484,6 @@ maybe_log_offset(double offset)
}
fprintf(p, "Subject: chronyd reports change to system clock on node [%s]\n", host);
fputs("\n", p);
now = time(NULL);
stm = *localtime(&now);
strftime(buffer, sizeof(buffer), "On %A, %d %B %Y\n with the system clock reading %H:%M:%S (%Z)", &stm);
fputs(buffer, p);
@@ -462,20 +519,109 @@ maybe_make_step()
/* ================================================== */
static void
update_leap_status(NTP_Leap leap)
static int
is_offset_ok(double offset)
{
if (max_offset_delay < 0)
return 1;
if (max_offset_delay > 0) {
max_offset_delay--;
return 1;
}
offset = fabs(offset);
if (offset > max_offset) {
LOG(LOGS_WARN, LOGF_Reference,
"Adjustment of %.3f seconds exceeds the allowed maximum of %.3f seconds (%s) ",
offset, max_offset, !max_offset_ignore ? "exiting" : "ignored");
if (!max_offset_ignore)
SCH_QuitProgram();
else if (max_offset_ignore > 0)
max_offset_ignore--;
return 0;
}
return 1;
}
/* ================================================== */
static NTP_Leap
get_tz_leap(time_t when)
{
struct tm stm;
time_t t;
char *tz_env, tz_orig[128];
/* Do this check at most twice a day */
when = when / (12 * 3600) * (12 * 3600);
if (last_tz_leap_check == when)
return tz_leap;
last_tz_leap_check = when;
tz_leap = LEAP_Normal;
stm = *gmtime(&when);
/* Check for leap second only in the latter half of June and December */
if (stm.tm_mon == 5 && stm.tm_mday > 14)
stm.tm_mday = 30;
else if (stm.tm_mon == 11 && stm.tm_mday > 14)
stm.tm_mday = 31;
else
return tz_leap;
/* Temporarily switch to the timezone containing leap seconds */
tz_env = getenv("TZ");
if (tz_env) {
if (strlen(tz_env) >= sizeof (tz_orig))
return tz_leap;
strcpy(tz_orig, tz_env);
}
setenv("TZ", leap_tzname, 1);
tzset();
/* Set the time to 23:59:60 and see how it overflows in mktime() */
stm.tm_sec = 60;
stm.tm_min = 59;
stm.tm_hour = 23;
t = mktime(&stm);
if (tz_env)
setenv("TZ", tz_orig, 1);
else
unsetenv("TZ");
tzset();
if (t == -1)
return tz_leap;
if (stm.tm_sec == 60)
tz_leap = LEAP_InsertSecond;
else if (stm.tm_sec == 1)
tz_leap = LEAP_DeleteSecond;
return tz_leap;
}
/* ================================================== */
static void
update_leap_status(NTP_Leap leap, time_t now)
{
time_t now;
struct tm stm;
int leap_sec;
leap_sec = 0;
if (leap_tzname && now && leap == LEAP_Normal)
leap = get_tz_leap(now);
if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
/* Insert/delete leap second only on June 30 or December 31
and in other months ignore the leap status completely */
now = time(NULL);
stm = *gmtime(&now);
if (stm.tm_mon != 5 && stm.tm_mon != 11) {
@@ -501,11 +647,16 @@ update_leap_status(NTP_Leap leap)
/* ================================================== */
static void
write_log(struct timeval *ref_time, char *ref, int stratum, double freq, double skew, double offset)
write_log(struct timeval *ref_time, char *ref, int stratum, NTP_Leap leap,
double freq, double skew, double offset, int combined_sources,
double offset_sd, double uncorrected_offset)
{
const char leap_codes[4] = {'N', '+', '-', '?'};
if (logfileid != -1) {
LOG_FileWrite(logfileid, "%s %-15s %2d %10.3f %10.3f %10.3e",
UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew, offset);
LOG_FileWrite(logfileid, "%s %-15s %2d %10.3f %10.3f %10.3e %1c %2d %10.3e %10.3e",
UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew,
offset, leap_codes[leap], combined_sources, offset_sd,
uncorrected_offset);
}
}
@@ -514,10 +665,12 @@ write_log(struct timeval *ref_time, char *ref, int stratum, double freq, double
void
REF_SetReference(int stratum,
NTP_Leap leap,
unsigned long ref_id,
int combined_sources,
uint32_t ref_id,
IPAddr *ref_ip,
struct timeval *ref_time,
double offset,
double offset_sd,
double frequency,
double skew,
double root_delay,
@@ -529,19 +682,20 @@ REF_SetReference(int stratum,
double old_weight, new_weight, sum_weight;
double delta_freq1, delta_freq2;
double skew1, skew2;
double our_offset;
double our_frequency;
double abs_freq_ppm;
double update_interval;
double elapsed;
struct timeval now;
double correction_rate;
double uncorrected_offset;
struct timeval now, raw_now, ev_now, ev_raw_now;
assert(initialised);
/* Avoid getting NaNs */
if (skew < 1e-12)
skew = 1e-12;
if (our_skew < 1e-12)
our_skew = 1e-12;
/* Guard against dividing by zero */
if (skew < MIN_SKEW)
skew = MIN_SKEW;
/* If we get a serious rounding error in the source stats regression
processing, there is a remote chance that the skew argument is a
@@ -561,8 +715,20 @@ REF_SetReference(int stratum,
}
}
LCL_ReadRawTime(&raw_now);
are_we_synchronised = 1;
/* This is cheaper than calling LCL_CookTime */
SCH_GetLastEventTime(&ev_now, NULL, &ev_raw_now);
UTI_DiffTimevalsToDouble(&uncorrected_offset, &ev_now, &ev_raw_now);
UTI_AddDoubleToTimeval(&raw_now, uncorrected_offset, &now);
UTI_DiffTimevalsToDouble(&elapsed, &now, ref_time);
our_offset = offset + elapsed * frequency;
if (!is_offset_ok(our_offset))
return;
are_we_synchronised = leap != LEAP_Unsynchronised ? 1 : 0;
our_stratum = stratum + 1;
our_ref_id = ref_id;
if (ref_ip)
@@ -573,16 +739,34 @@ REF_SetReference(int stratum,
our_root_delay = root_delay;
our_root_dispersion = root_dispersion;
LCL_ReadCookedTime(&now, NULL);
UTI_DiffTimevalsToDouble(&elapsed, &now, ref_time);
our_offset = offset + elapsed * frequency;
if (last_ref_update.tv_sec) {
UTI_DiffTimevalsToDouble(&update_interval, &now, &last_ref_update);
if (update_interval < 0.0)
update_interval = 0.0;
} else {
update_interval = 0.0;
}
last_ref_update = now;
update_leap_status(leap);
/* We want to correct the offset quickly, but we also want to keep the
frequency error caused by the correction itself low.
Define correction rate as the area of the region bounded by the graph of
offset corrected in time. Set the rate so that the time needed to correct
an offset equal to the current sourcestats stddev will be equal to the
update interval multiplied by the correction time ratio (assuming linear
adjustment). The offset and the time needed to make the correction are
inversely proportional.
This is only a suggestion and it's up to the system driver how the
adjustment will be executed. */
correction_rate = correction_time_ratio * 0.5 * offset_sd * update_interval;
/* Eliminate updates that are based on totally unreliable frequency
information */
information. Ignore this limit with manual reference. */
if (fabs(skew) < max_update_skew) {
if (fabs(skew) < max_update_skew || leap == LEAP_Unsynchronised) {
previous_skew = our_skew;
new_skew = skew;
@@ -594,9 +778,10 @@ REF_SetReference(int stratum,
the local module. */
new_freq = frequency;
/* Set new frequency based on weighted average of old and new skew. */
/* Set new frequency based on weighted average of old and new skew. With
manual reference the old frequency has no weight. */
old_weight = 1.0 / Sqr(previous_skew);
old_weight = leap != LEAP_Unsynchronised ? 1.0 / Sqr(previous_skew) : 0.0;
new_weight = 3.0 / Sqr(new_skew);
sum_weight = old_weight + new_weight;
@@ -612,20 +797,20 @@ REF_SetReference(int stratum,
our_residual_freq = new_freq - our_frequency;
maybe_log_offset(our_offset);
LCL_AccumulateFrequencyAndOffset(our_frequency, our_offset);
LCL_AccumulateFrequencyAndOffset(our_frequency, our_offset, correction_rate);
} else {
#if 0
LOG(LOGS_INFO, LOGF_Reference, "Skew %f too large to track, offset=%f", skew, our_offset);
#endif
maybe_log_offset(our_offset);
LCL_AccumulateOffset(our_offset);
LCL_AccumulateOffset(our_offset, correction_rate);
our_residual_freq = frequency;
}
update_leap_status(leap, raw_now.tv_sec);
maybe_log_offset(our_offset, raw_now.tv_sec);
maybe_make_step();
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
@@ -633,11 +818,13 @@ REF_SetReference(int stratum,
write_log(&now,
our_ref_ip.family != IPADDR_UNSPEC ? UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
our_stratum,
our_leap_status,
abs_freq_ppm,
1.0e6*our_skew,
our_offset);
UTI_DiffTimevalsToDouble(&update_interval, &now, &last_ref_update);
our_offset,
combined_sources,
offset_sd,
uncorrected_offset);
if (drift_file) {
/* Update drift file at most once per hour */
@@ -653,14 +840,17 @@ REF_SetReference(int stratum,
update_fb_drifts(abs_freq_ppm, update_interval);
}
last_ref_update = now;
last_ref_update_interval = update_interval;
last_offset = our_offset;
/* And now set the freq and offset to zero */
our_frequency = 0.0;
our_offset = 0.0;
return;
/* Update the moving average of squares of offset, quickly on start */
if (avg2_moving) {
avg2_offset += 0.1 * (our_offset * our_offset - avg2_offset);
} else {
if (avg2_offset > 0.0 && avg2_offset < our_offset * our_offset)
avg2_moving = 1;
avg2_offset = our_offset * our_offset;
}
}
/* ================================================== */
@@ -674,32 +864,13 @@ REF_SetManualReference
double skew
)
{
double abs_freq_ppm;
uint32_t manual_refid = 0x4D414E55; /* MANU */
/* We are not synchronised to an external source, as such. This is
only supposed to be used with the local source option, really
... */
are_we_synchronised = 0;
our_skew = skew;
our_residual_freq = 0.0;
maybe_log_offset(offset);
LCL_AccumulateFrequencyAndOffset(frequency, offset);
maybe_make_step();
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
write_log(ref_time,
"127.127.1.1",
our_stratum,
abs_freq_ppm,
1.0e6*our_skew,
our_offset);
if (drift_file) {
update_drift_file(abs_freq_ppm, our_skew);
}
REF_SetReference(0, LEAP_Unsynchronised, 1, manual_refid, NULL,
ref_time, offset, 0.0, frequency, skew, 0.0, 0.0);
}
/* ================================================== */
@@ -708,26 +879,32 @@ void
REF_SetUnsynchronised(void)
{
/* Variables required for logging to statistics log */
struct timeval now;
struct timeval now, now_raw;
double uncorrected_offset;
assert(initialised);
LCL_ReadCookedTime(&now, NULL);
/* This is cheaper than calling LCL_CookTime */
SCH_GetLastEventTime(&now, NULL, &now_raw);
UTI_DiffTimevalsToDouble(&uncorrected_offset, &now, &now_raw);
if (fb_drifts) {
schedule_fb_drift(&now);
}
update_leap_status(LEAP_Unsynchronised, 0);
are_we_synchronised = 0;
write_log(&now,
"0.0.0.0",
0,
our_leap_status,
LCL_ReadAbsoluteFrequency(),
1.0e6*our_skew,
0.0);
are_we_synchronised = 0;
update_leap_status(LEAP_Unsynchronised);
0.0,
0,
0.0,
uncorrected_offset);
}
/* ================================================== */
@@ -739,7 +916,7 @@ REF_GetReferenceParams
int *is_synchronised,
NTP_Leap *leap_status,
int *stratum,
unsigned long *ref_id,
uint32_t *ref_id,
struct timeval *ref_time,
double *root_delay,
double *root_dispersion
@@ -792,7 +969,7 @@ REF_GetReferenceParams
*leap_status = LEAP_Unsynchronised;
*stratum = 0;
*ref_id = 0UL;
*ref_id = 0;
ref_time->tv_sec = ref_time->tv_usec = 0;
/* These values seem to be standard for a client, and
any peer or client of ours will ignore them anyway because
@@ -867,6 +1044,22 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
LCL_GetOffsetCorrection(&now_raw, &correction, NULL);
UTI_AddDoubleToTimeval(&now_raw, correction, &now_cooked);
rep->ref_id = 0;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = 0;
rep->leap_status = our_leap_status;
rep->ref_time.tv_sec = 0;
rep->ref_time.tv_usec = 0;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 0.0;
rep->skew_ppm = 0.0;
rep->root_delay = 0.0;
rep->root_dispersion = 0.0;
rep->last_update_interval = last_ref_update_interval;
rep->last_offset = last_offset;
rep->rms_offset = sqrt(avg2_offset);
if (are_we_synchronised) {
UTI_DiffTimevalsToDouble(&elapsed, &now_cooked, &our_ref_time);
@@ -876,8 +1069,6 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
rep->ip_addr = our_ref_ip;
rep->stratum = our_stratum;
rep->ref_time = our_ref_time;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 1.0e6 * our_residual_freq;
rep->skew_ppm = 1.0e6 * our_skew;
rep->root_delay = our_root_delay;
@@ -889,26 +1080,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = local_stratum;
rep->ref_time = now_cooked;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 0.0;
rep->skew_ppm = 0.0;
rep->root_delay = 0.0;
rep->root_dispersion = LCL_GetSysPrecisionAsQuantum();
} else {
rep->ref_id = 0UL;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = 0;
rep->ref_time.tv_sec = 0;
rep->ref_time.tv_usec = 0;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 0.0;
rep->skew_ppm = 0.0;
rep->root_delay = 0.0;
rep->root_dispersion = 0.0;
}
}

View File

@@ -71,7 +71,7 @@ extern void REF_GetReferenceParams
int *is_synchronised,
NTP_Leap *leap,
int *stratum,
unsigned long *ref_id,
uint32_t *ref_id,
struct timeval *ref_time,
double *root_delay,
double *root_dispersion
@@ -105,10 +105,12 @@ extern void REF_SetReference
(
int stratum,
NTP_Leap leap,
unsigned long ref_id,
int combined_sources,
uint32_t ref_id,
IPAddr *ref_ip,
struct timeval *ref_time,
double offset,
double offset_sd,
double frequency,
double skew,
double root_delay,

View File

@@ -26,11 +26,9 @@
*/
#include <assert.h>
#include <math.h>
#include "config.h"
#include <stdio.h>
#include <string.h>
#include "sysincl.h"
#include "regress.h"
#include "logging.h"
@@ -101,8 +99,6 @@ RGR_WeightedRegression
*sb0 = sqrt(*s2 / W + aa * aa);
*s2 *= (n / W); /* Giving weighted average of variances */
return;
}
/* ================================================== */
@@ -226,6 +222,9 @@ RGR_FindBestRegression
int m, /* number of extra samples in x and y arrays
(negative index) which can be used to
extend runs test */
int min_samples, /* minimum number of samples to be kept after
changing the starting index to pass the runs
test */
/* And now the results */
@@ -297,10 +296,12 @@ RGR_FindBestRegression
/* Count number of runs */
nruns = n_runs_from_residuals(resid, n - resid_start);
if (nruns > critical_runs[n - resid_start] || n - start <= MIN_SAMPLES_FOR_REGRESS) {
if (resid_start < 0) {
if (nruns > critical_runs[n - resid_start] ||
n - start <= MIN_SAMPLES_FOR_REGRESS ||
n - start <= min_samples) {
if (start != resid_start) {
/* Ignore extra samples in returned nruns */
nruns = n_runs_from_residuals(resid - resid_start, n);
nruns = n_runs_from_residuals(resid - resid_start + start, n - start);
}
break;
} else {
@@ -420,7 +421,7 @@ find_ordered_entry(double *x, int n, int index)
{
int flags[MAX_POINTS];
bzero(flags, n * sizeof(int));
memset(flags, 0, n * sizeof(int));
return find_ordered_entry_with_flags(x, n, index, flags);
}
#endif
@@ -586,7 +587,7 @@ RGR_FindBestRobustRegression
Estimate standard deviation of b and expand range about b based
on that. */
sb = sqrt(s2 * W/V);
if (sb > 0.0) {
if (sb > tol) {
incr = 3.0 * sb;
} else {
incr = 3.0 * tol;
@@ -596,6 +597,11 @@ RGR_FindBestRobustRegression
bhi = b;
do {
/* Make sure incr is significant to blo and bhi */
while (bhi + incr == bhi || blo - incr == blo) {
incr *= 2;
}
blo -= incr;
bhi += incr;
@@ -603,8 +609,8 @@ RGR_FindBestRobustRegression
eval_robust_residual(x + start, y + start, n_points, blo, &a, &rlo);
eval_robust_residual(x + start, y + start, n_points, bhi, &a, &rhi);
} while (rlo * rhi > 0.0); /* fn vals have same sign, i.e. root not
in interval. */
} while (rlo * rhi >= 0.0); /* fn vals have same sign or one is zero,
i.e. root not in interval (rlo, rhi). */
/* OK, so the root for b lies in (blo, bhi). Start bisecting */
do {
@@ -621,7 +627,7 @@ RGR_FindBestRobustRegression
} else {
assert(0);
}
} while ((bhi - blo) > tol);
} while ((bhi - blo) > tol && (bmid - blo) * (bhi - bmid) > 0.0);
*b0 = a;
*b1 = bmid;

View File

@@ -80,6 +80,9 @@ RGR_FindBestRegression
int m, /* number of extra samples in x and y arrays
(negative index) which can be used to
extend runs test */
int min_samples, /* minimum number of samples to be kept after
changing the starting index to pass the runs
test */
/* And now the results */

View File

@@ -37,8 +37,10 @@ typedef struct {
int stratum;
int poll;
enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode;
enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE} state;
enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE, RPT_OUTLIER} state;
enum {RPT_NORMAL, RPT_PREFER, RPT_NOSELECT} sel_option;
int reachability;
unsigned long latest_meas_ago; /* seconds */
double orig_latest_meas; /* seconds */
double latest_meas; /* seconds */
@@ -46,20 +48,24 @@ typedef struct {
} RPT_SourceReport ;
typedef struct {
unsigned long ref_id;
uint32_t ref_id;
IPAddr ip_addr;
unsigned long stratum;
unsigned long leap_status;
struct timeval ref_time;
double current_correction;
double last_offset;
double rms_offset;
double freq_ppm;
double resid_freq_ppm;
double skew_ppm;
double root_delay;
double root_dispersion;
double last_update_interval;
} RPT_TrackingReport;
typedef struct {
unsigned long ref_id;
uint32_t ref_id;
IPAddr ip_addr;
unsigned long n_samples;
unsigned long n_runs;
@@ -113,6 +119,7 @@ typedef struct {
int offline;
int burst_online;
int burst_offline;
int unresolved;
} RPT_ActivityReport;
#endif /* GOT_REPORTS_H */

5
rtc.c
View File

@@ -23,6 +23,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "rtc.h"
@@ -106,9 +108,6 @@ RTC_Initialise(void)
} else {
driver_initialised = 0;
}
return;
}
/* ================================================== */

View File

@@ -3,6 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -26,25 +27,10 @@
*/
#if defined LINUX
#include "config.h"
#ifdef sparc
#define __KERNEL__
#endif
#include "sysincl.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <linux/rtc.h>
#include "logging.h"
@@ -186,7 +172,6 @@ discard_samples(int new_first)
memmove(system_times, system_times + new_first, n_to_save * sizeof(struct timeval));
n_samples = n_to_save;
return;
}
/* ================================================== */
@@ -214,8 +199,6 @@ accumulate_sample(time_t rtc, struct timeval *sys)
++n_samples_since_regression;
}
++n_samples;
return;
}
/* ================================================== */
@@ -467,10 +450,14 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
}
/* Gain rate is written out in ppm */
fprintf(out, "%1d %ld %.6f %.3f\n",
valid,ref_time, offset, 1.0e6 * rate);
fclose(out);
if ((fprintf(out, "%1d %ld %.6f %.3f\n",
valid,ref_time, offset, 1.0e6 * rate) < 0) |
fclose(out)) {
Free(temp_coefs_file_name);
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not write to temporary RTC file %s.tmp",
coefs_file_name);
return RTC_ST_BADFILE;
}
/* Clone the file attributes from the existing file if there is one. */
@@ -505,62 +492,6 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
int
RTC_Linux_Initialise(void)
{
int major, minor, patch;
/* Check whether we can support the real time clock.
Linux 1.2.x - haven't checked yet
Linux 1.3.x - don't know, haven't got a system to look at
Linux 2.0.x - For x<=31, using any variant of the adjtimex() call
sets the kernel into a mode where the RTC was updated every 11
minutes. The only way to escape this is to use settimeofday().
Since we need to have sole control over the RTC to be able to
measure its drift rate, and there is no 'notify' callback to warn
you that the kernel is going to do this, I can't see a way to
support this.
Linux 2.0.x - For x>=32 the adjtimex()/RTC behaviour was
modified, so that as long as the STA_UNSYNC flag is set the RTC
is left alone. This is the mode we exploit here, so that the RTC
continues to go its own sweet way, unless we make updates to it
from this module.
Linux 2.1.x - don't know, haven't got a system to look at.
Linux 2.2.x, 2.3.x and 2.4.x are believed to be OK for all
patch levels
*/
SYS_Linux_GetKernelVersion(&major, &minor, &patch);
/* Obviously this test can get more elaborate when we know about
more system types. */
if (major != 2) {
return 0;
} else {
switch (minor) {
case 0:
if (patch <= 31) {
return 0;
}
break;
case 1:
return 0;
break;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
break; /* OK for all patch levels */
}
}
/* Setup details depending on configuration options */
setup_config();
@@ -718,7 +649,7 @@ handle_initial_trim(void)
sys_error_now = rtc_error_now - coef_seconds_fast;
LOG(LOGS_INFO, LOGF_RtcLinux, "System trim from RTC = %f", sys_error_now);
LCL_AccumulateOffset(sys_error_now);
LCL_AccumulateOffset(sys_error_now, 0.0);
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "No valid file coefficients, cannot trim system time");
}
@@ -728,8 +659,6 @@ handle_initial_trim(void)
(after_init_hook)(after_init_hook_arg);
operating_mode = OM_NORMAL;
return;
}
/* ================================================== */
@@ -749,6 +678,7 @@ handle_relock_after_trim(void)
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not do regression after trim");
}
coefs_valid = 0;
n_samples = 0;
n_samples_since_regression = 0;
operating_mode = OM_NORMAL;
@@ -843,7 +773,7 @@ read_from_device(void *any)
/* Read RTC time, sandwiched between two polls of the system clock
so we can bound any error. */
SCH_GetFileReadyTime(&sys_time, NULL);
SCH_GetLastEventTime(&sys_time, NULL, NULL);
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
if (status < 0) {
@@ -988,7 +918,7 @@ RTC_Linux_TimePreInit(void)
time_t rtc_t, estimated_correct_rtc_t;
long interval;
double accumulated_error = 0.0;
struct timeval new_sys_time;
struct timeval new_sys_time, old_sys_time;
coefs_file_name = CNF_GetRtcFile();
@@ -1023,8 +953,6 @@ RTC_Linux_TimePreInit(void)
accumulated_error = file_ref_offset + (double)(interval) * 1.0e-6 * file_rate_ppm;
/* Correct time */
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error);
estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
} else {
estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
@@ -1033,9 +961,18 @@ RTC_Linux_TimePreInit(void)
new_sys_time.tv_sec = estimated_correct_rtc_t;
new_sys_time.tv_usec = 0;
/* Tough luck if this fails */
if (settimeofday(&new_sys_time, NULL) < 0) {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not settimeofday");
/* Set system time only if the step is larger than 1 second */
if (!(gettimeofday(&old_sys_time, NULL) < 0) &&
(old_sys_time.tv_sec - new_sys_time.tv_sec > 1 ||
old_sys_time.tv_sec - new_sys_time.tv_sec < -1)) {
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error);
/* Tough luck if this fails */
if (settimeofday(&new_sys_time, NULL) < 0) {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not settimeofday");
}
}
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");
@@ -1098,6 +1035,11 @@ RTC_Linux_Trim(void)
n_samples = 0;
operating_mode = OM_AFTERTRIM;
/* Estimate the offset in case writertc is called or chronyd
is terminated during rapid sampling */
coef_seconds_fast = -now.tv_usec / 1e6 + 0.5;
coef_ref_time = now.tv_sec;
/* And start rapid sampling, interrupts on now */
if (timeout_running) {
SCH_RemoveTimeout(timeout_id);
@@ -1109,7 +1051,3 @@ RTC_Linux_Trim(void)
return 1;
}
/* ================================================== */
#endif /* defined LINUX */

View File

@@ -28,8 +28,6 @@
#include "reports.h"
#if defined LINUX
extern int RTC_Linux_Initialise(void);
extern void RTC_Linux_Finalise(void);
extern void RTC_Linux_TimePreInit(void);
@@ -44,6 +42,4 @@ extern int RTC_Linux_Trim(void);
extern void RTC_Linux_CycleLogFile(void);
#endif /* defined LINUX */
#endif /* _GOT_RTC_LINUX_H */

153
sched.c
View File

@@ -26,6 +26,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "sched.h"
@@ -68,9 +70,9 @@ typedef struct {
static FileHandlerEntry file_handlers[FD_SET_SIZE];
/* Last timestamp when a file descriptor became readable */
static struct timeval last_fdready;
static double last_fdready_err;
/* Timestamp when last select() returned */
static struct timeval last_select_ts, last_select_ts_raw;
static double last_select_ts_err;
/* ================================================== */
@@ -129,8 +131,6 @@ handle_slew(struct timeval *raw,
void
SCH_Initialise(void)
{
struct timeval tv;
FD_ZERO(&read_fds);
n_read_fds = 0;
@@ -144,12 +144,12 @@ SCH_Initialise(void)
LCL_AddParameterChangeHandler(handle_slew, NULL);
LCL_ReadRawTime(&tv);
srandom(tv.tv_sec * tv.tv_usec);
LCL_ReadRawTime(&last_select_ts_raw);
last_select_ts = last_select_ts_raw;
srandom(last_select_ts.tv_sec << 16 ^ last_select_ts.tv_usec);
initialised = 1;
return;
}
@@ -158,7 +158,6 @@ SCH_Initialise(void)
void
SCH_Finalise(void) {
initialised = 0;
return; /* Nothing to do for now */
}
/* ================================================== */
@@ -185,8 +184,6 @@ SCH_AddInputFileHandler
if ((fd + 1) > one_highest_fd) {
one_highest_fd = fd + 1;
}
return;
}
@@ -217,19 +214,20 @@ SCH_RemoveInputFileHandler(int fd)
}
one_highest_fd = fd_to_check;
return;
}
/* ================================================== */
void
SCH_GetFileReadyTime(struct timeval *tv, double *err)
SCH_GetLastEventTime(struct timeval *cooked, double *err, struct timeval *raw)
{
*tv = last_fdready;
if (err)
*err = last_fdready_err;
if (cooked) {
*cooked = last_select_ts;
if (err)
*err = last_select_ts_err;
}
if (raw)
*raw = last_select_ts_raw;
}
/* ================================================== */
@@ -263,7 +261,6 @@ release_tqe(TimerQueueEntry *node)
{
node->next = tqe_free_list;
tqe_free_list = node;
return;
}
/* ================================================== */
@@ -316,6 +313,7 @@ SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArg
struct timeval now, then;
assert(initialised);
assert(delay >= 0.0);
LCL_ReadRawTime(&now);
UTI_AddDoubleToTimeval(&now, delay, &then);
@@ -337,6 +335,7 @@ SCH_AddTimeoutInClass(double min_delay, double separation, double randomness,
double new_min_delay;
assert(initialised);
assert(min_delay >= 0.0);
assert(class < SCH_NumberOfClasses);
if (randomness > 0.0) {
@@ -426,18 +425,26 @@ SCH_RemoveTimeout(SCH_TimeoutID id)
}
/* ================================================== */
/* The current time (now) has to be passed in from the
caller to avoid race conditions */
/* Try to dispatch any timeouts that have already gone by, and
keep going until all are done. (The earlier ones may take so
long to do that the later ones come around by the time they are
completed). */
static int
static void
dispatch_timeouts(struct timeval *now) {
TimerQueueEntry *ptr;
SCH_TimeoutHandler handler;
SCH_ArbitraryArgument arg;
int n_done = 0;
int n_done = 0, n_entries_on_start = n_timer_queue_entries;
while (1) {
LCL_ReadRawTime(now);
if (!(n_timer_queue_entries > 0 &&
UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) {
break;
}
if ((n_timer_queue_entries > 0) &&
(UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) {
ptr = timer_queue.next;
last_class_dispatch[ptr->class] = *now;
@@ -452,10 +459,17 @@ dispatch_timeouts(struct timeval *now) {
/* Increment count of timeouts handled */
++n_done;
/* If more timeouts were handled than there were in the timer queue on
start and there are now, assume some code is scheduling timeouts with
negative delays and abort. Make the actual limit higher in case the
machine is temporarily overloaded and dispatching the handlers takes
more time than was delay of a scheduled timeout. */
if (n_done > n_timer_queue_entries * 4 &&
n_done > n_entries_on_start * 4) {
LOG_FATAL(LOGF_Scheduler, "Possible infinite loop in scheduling");
}
}
return n_done;
}
/* ================================================== */
@@ -493,12 +507,11 @@ handle_slew(struct timeval *raw,
void *anything)
{
TimerQueueEntry *ptr;
double delta;
int i;
if (is_step_change) {
/* We're not interested in anything else - it won't affect the
functionality of timer event dispatching. If a step change
occurs, just shift all the timeouts by the offset */
/* If a step change occurs, just shift all raw time stamps by the offset */
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
UTI_AddDoubleToTimeval(&ptr->tv, -doffset, &ptr->tv);
@@ -507,7 +520,39 @@ handle_slew(struct timeval *raw,
for (i = 0; i < SCH_NumberOfClasses; i++) {
UTI_AddDoubleToTimeval(&last_class_dispatch[i], -doffset, &last_class_dispatch[i]);
}
UTI_AddDoubleToTimeval(&last_select_ts_raw, -doffset, &last_select_ts_raw);
}
UTI_AdjustTimeval(&last_select_ts, cooked, &last_select_ts, &delta, dfreq, doffset);
}
/* ================================================== */
/* Try to handle unexpected backward time jump */
static void
recover_backjump(struct timeval *raw, struct timeval *cooked, int timeout)
{
double diff, err;
UTI_DiffTimevalsToDouble(&diff, &last_select_ts_raw, raw);
if (n_timer_queue_entries > 0) {
UTI_DiffTimevalsToDouble(&err, &(timer_queue.next->tv), &last_select_ts_raw);
} else {
err = 0.0;
}
diff += err;
if (timeout) {
err = 1.0;
}
LOG(LOGS_WARN, LOGF_Scheduler, "Backward time jump detected! (correction %.1f +- %.1f seconds)", diff, err);
LCL_NotifyExternalTimeStep(raw, cooked, diff, err);
}
/* ================================================== */
@@ -516,9 +561,10 @@ void
SCH_MainLoop(void)
{
fd_set rd;
int status;
int status, errsv;
struct timeval tv, *ptv;
struct timeval now;
struct timeval now, cooked;
double err;
assert(initialised);
@@ -527,20 +573,15 @@ SCH_MainLoop(void)
/* Copy current set of read file descriptors */
memcpy((void *) &rd, (void *) &read_fds, sizeof(fd_set));
/* Try to dispatch any timeouts that have already gone by, and
keep going until all are done. (The earlier ones may take so
long to do that the later ones come around by the time they are
completed). */
do {
LCL_ReadRawTime(&now);
} while (dispatch_timeouts(&now) > 0);
/* Dispatch timeouts and fill now with current raw time */
dispatch_timeouts(&now);
/* Check whether there is a timeout and set it up */
if (n_timer_queue_entries > 0) {
UTI_DiffTimevals(&tv, &(timer_queue.next->tv), &now);
ptv = &tv;
assert(tv.tv_sec > 0 || tv.tv_usec > 0);
} else {
ptv = NULL;
@@ -548,24 +589,33 @@ SCH_MainLoop(void)
/* if there are no file descriptors being waited on and no
timeout set, this is clearly ridiculous, so stop the run */
if (!ptv && (n_read_fds == 0)) {
LOG_FATAL(LOGF_Scheduler, "No descriptors or timeout to wait for");
}
assert(ptv || n_read_fds);
status = select(one_highest_fd, &rd, NULL, NULL, ptv);
errsv = errno;
LCL_ReadRawTime(&now);
LCL_CookTime(&now, &cooked, &err);
/* Check if time didn't jump backwards */
if (last_select_ts_raw.tv_sec > now.tv_sec + 1) {
recover_backjump(&now, &cooked, status == 0);
}
last_select_ts_raw = now;
last_select_ts = cooked;
last_select_ts_err = err;
if (status < 0) {
assert(need_to_exit);
if (!need_to_exit && errsv != EINTR) {
LOG_FATAL(LOGF_Scheduler, "select() failed : %s", strerror(errsv));
}
} else if (status > 0) {
/* A file descriptor is ready to read */
LCL_ReadCookedTime(&last_fdready, &last_fdready_err);
dispatch_filehandlers(status, &rd);
} else {
assert(status == 0);
/* No descriptors readable, timeout must have elapsed.
Therefore, tv must be non-null */
assert(ptv);
@@ -576,9 +626,6 @@ SCH_MainLoop(void)
}
}
return;
}
/* ================================================== */

View File

@@ -58,9 +58,8 @@ extern void SCH_AddInputFileHandler
);
extern void SCH_RemoveInputFileHandler(int fd);
/* Get the time (cooked) when file descriptor became ready, intended for use
in file handlers */
extern void SCH_GetFileReadyTime(struct timeval *tv, double *err);
/* Get the time stamp taken after a file descriptor became ready or a timeout expired */
extern void SCH_GetLastEventTime(struct timeval *cooked, double *err, struct timeval *raw);
/* This queues a timeout to elapse at a given (raw) local time */
extern SCH_TimeoutID SCH_AddTimeout(struct timeval *tv, SCH_TimeoutHandler, SCH_ArbitraryArgument);

182
sources.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
* Copyright (C) Miroslav Lichvar 2011-2013
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -28,6 +28,8 @@
*/
#include "config.h"
#include "sysincl.h"
#include "sources.h"
@@ -42,6 +44,7 @@
#include "reports.h"
#include "nameserv.h"
#include "mkdirpp.h"
#include "sched.h"
/* ================================================== */
/* Flag indicating that we are initialised */
@@ -53,10 +56,7 @@ struct SelectInfo {
int stratum;
int select_ok;
double variance;
double root_delay;
double root_dispersion;
double root_distance;
double best_offset;
double lo_limit;
double hi_limit;
};
@@ -82,8 +82,8 @@ struct SRC_Instance_Record {
SST_Stats stats;
NTP_Leap leap_status; /* Leap status */
int index; /* Index back into the array of source */
unsigned long ref_id; /* The reference ID of this source
(i.e. its IP address, NOT the
uint32_t ref_id; /* The reference ID of this source
(i.e. from its IP address, NOT the
reference _it_ is sync'd to) */
IPAddr *ip_addr; /* Its IP address if NTP source */
@@ -93,6 +93,12 @@ struct SRC_Instance_Record {
/* Reachability register */
int reachability;
/* Flag indicating that only few samples were accumulated so far */
int beginning;
/* Updates left before allowing combining */
int outlier;
/* Flag indicating the status of the source */
SRC_Status status;
@@ -135,8 +141,12 @@ static int selected_source_index; /* Which source index is currently
/* Score needed to replace the currently selected source */
#define SCORE_LIMIT 10.0
/* Number of updates needed to reset the outlier status */
#define OUTLIER_PENALTY 32
static double reselect_distance;
static double stratum_weight;
static double combine_limit;
/* ================================================== */
/* Forward prototype */
@@ -159,12 +169,11 @@ void SRC_Initialise(void) {
selected_source_index = INVALID_SOURCE;
reselect_distance = CNF_GetReselectDistance();
stratum_weight = CNF_GetStratumWeight();
combine_limit = CNF_GetCombineLimit();
initialised = 1;
LCL_AddParameterChangeHandler(slew_sources, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
return;
}
/* ================================================== */
@@ -174,14 +183,13 @@ void SRC_Finalise(void)
LCL_RemoveParameterChangeHandler(slew_sources, NULL);
LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
initialised = 0;
return;
}
/* ================================================== */
/* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */
SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr)
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr)
{
SRC_Instance result;
@@ -211,6 +219,8 @@ SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, SRC_Sele
result->ip_addr = addr;
result->selectable = 0;
result->reachability = 0;
result->beginning = 1;
result->outlier = 0;
result->status = SRC_BAD_STATS;
result->type = type;
result->sel_score = 1.0;
@@ -266,7 +276,6 @@ void SRC_GetFrequencyRange(SRC_Instance instance, double *lo, double *hi)
assert(initialised);
SST_GetFrequencyRange(instance->stats, lo, hi);
return;
}
/* ================================================== */
@@ -309,8 +318,6 @@ void SRC_AccumulateSample
SST_DoNewRegression(inst->stats);
/* And redo clock selection */
SRC_SelectSource(inst->ref_id);
return;
}
/* ================================================== */
@@ -357,6 +364,10 @@ SRC_UpdateReachability(SRC_Instance inst, int reachable)
inst->reachability |= !!reachable;
inst->reachability &= ~(-1 << REACH_BITS);
/* The beginning is over when the first sample is at the end of the register */
if (inst->reachability & (1 << (REACH_BITS - 1)))
inst->beginning = 0;
if (!reachable && inst->index == selected_source_index) {
/* Try to select a better source */
SRC_SelectSource(0);
@@ -413,15 +424,94 @@ source_to_string(SRC_Instance inst)
return NULL;
}
/* ================================================== */
static int
combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
double *offset_sd, double *frequency, double *skew)
{
struct timeval src_ref_time;
double src_offset, src_offset_sd, src_frequency, src_skew;
double src_root_delay, src_root_dispersion, elapsed;
double offset_weight, sum_offset_weight, sum_offset, sum2_offset_sd;
double frequency_weight, sum_frequency_weight, sum_frequency, inv_sum2_skew;
int i, index, combined;
if (n_sel_sources == 1)
return 1;
sum_offset_weight = sum_offset = sum2_offset_sd = 0.0;
sum_frequency_weight = sum_frequency = inv_sum2_skew = 0.0;
for (i = combined = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
SST_GetTrackingData(sources[index]->stats, &src_ref_time,
&src_offset, &src_offset_sd,
&src_frequency, &src_skew,
&src_root_delay, &src_root_dispersion);
/* Don't include this source if its distance is longer than the distance of
the selected source multiplied by the limit, their estimated frequencies
are not close, or it was recently marked as outlier */
if (index != selected_source_index &&
(sources[index]->sel_info.root_distance > combine_limit *
(reselect_distance + sources[selected_source_index]->sel_info.root_distance) ||
fabs(*frequency - src_frequency) >
combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) {
sources[index]->outlier = !sources[index]->beginning ? OUTLIER_PENALTY : 1;
} else if (sources[index]->outlier) {
sources[index]->outlier--;
}
if (sources[index]->outlier)
continue;
UTI_DiffTimevalsToDouble(&elapsed, ref_time, &src_ref_time);
src_offset += elapsed * src_frequency;
offset_weight = 1.0 / sources[index]->sel_info.root_distance;
frequency_weight = 1.0 / src_skew;
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Sources, "combining index=%d oweight=%e offset=%e sd=%e fweight=%e freq=%e skew=%e",
index, offset_weight, src_offset, src_offset_sd, frequency_weight, src_frequency, src_skew);
#endif
sum_offset_weight += offset_weight;
sum_offset += offset_weight * src_offset;
sum2_offset_sd += offset_weight * (src_offset_sd * src_offset_sd +
(src_offset - *offset) * (src_offset - *offset));
sum_frequency_weight += frequency_weight;
sum_frequency += frequency_weight * src_frequency;
inv_sum2_skew += 1.0 / (src_skew * src_skew);
combined++;
}
assert(combined);
*offset = sum_offset / sum_offset_weight;
*offset_sd = sqrt(sum2_offset_sd / sum_offset_weight);
*frequency = sum_frequency / sum_frequency_weight;
*skew = 1.0 / sqrt(inv_sum2_skew);
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Sources, "combined result offset=%e sd=%e freq=%e skew=%e",
*offset, *offset_sd, *frequency, *skew);
#endif
return combined;
}
/* ================================================== */
/* This function selects the current reference from amongst the pool
of sources we are holding.
Updates are only made to the local reference if a new source is selected
or match_addr is equal to the selected reference source address */
or match_refid is equal to the selected reference source refid */
void
SRC_SelectSource(unsigned long match_addr)
SRC_SelectSource(uint32_t match_refid)
{
int i, j, index, old_selected_index;
struct timeval now, ref_time;
@@ -430,7 +520,7 @@ SRC_SelectSource(unsigned long match_addr)
int n_endpoints, j1, j2;
double best_lo, best_hi;
int depth, best_depth;
int n_sel_sources;
int n_sel_sources, combined;
double distance, sel_src_distance;
int stratum, min_stratum;
struct SelectInfo *si;
@@ -452,7 +542,8 @@ SRC_SelectSource(unsigned long match_addr)
return;
}
LCL_ReadCookedTime(&now, NULL);
/* This is accurate enough and cheaper than calling LCL_ReadCookedTime */
SCH_GetLastEventTime(&now, NULL, NULL);
/* Step 1 - build intervals about each source */
n_endpoints = 0;
@@ -467,20 +558,16 @@ SRC_SelectSource(unsigned long match_addr)
si = &(sources[i]->sel_info);
SST_GetSelectionData(sources[i]->stats, &now,
&(si->stratum),
&(si->best_offset),
&(si->root_delay),
&(si->root_dispersion),
&(si->lo_limit),
&(si->hi_limit),
&(si->root_distance),
&(si->variance),
&(si->select_ok));
si->root_distance = si->root_dispersion + 0.5 * fabs(si->root_delay);
si->lo_limit = si->best_offset - si->root_distance;
si->hi_limit = si->best_offset + si->root_distance;
#if 0
LOG(LOGS_INFO, LOGF_Sources, "%s off=%f dist=%f lo=%f hi=%f",
LOG(LOGS_INFO, LOGF_Sources, "%s dist=%f lo=%f hi=%f",
source_to_string(sources[i]),
si->best_offset, si->root_distance,
si->root_distance,
si->lo_limit, si->hi_limit);
#endif
@@ -769,6 +856,7 @@ SRC_SelectSource(unsigned long match_addr)
/* Reset score for non-selectable sources */
if (sources[i]->status != SRC_SELECTABLE) {
sources[i]->sel_score = 1.0;
sources[i]->outlier = OUTLIER_PENALTY;
continue;
}
@@ -781,8 +869,8 @@ SRC_SelectSource(unsigned long match_addr)
/* Update score, but only for source pairs where one source
has a new sample */
if (sources[i]->ref_id == match_addr ||
sources[selected_source_index]->ref_id == match_addr) {
if (sources[i]->ref_id == match_refid ||
sources[selected_source_index]->ref_id == match_refid) {
sources[i]->sel_score *= sel_src_distance / distance;
@@ -801,7 +889,7 @@ SRC_SelectSource(unsigned long match_addr)
#if 0
LOG(LOGS_INFO, LOGF_Sources, "select score=%f refid=%lx match_refid=%lx status=%d dist=%f",
sources[i]->sel_score, sources[i]->ref_id, match_addr, sources[i]->status, distance);
sources[i]->sel_score, sources[i]->ref_id, match_refid, sources[i]->status, distance);
#endif
if (max_score < sources[i]->sel_score) {
@@ -832,29 +920,36 @@ SRC_SelectSource(unsigned long match_addr)
/* New source has been selected, reset all scores */
for (i=0; i < n_sources; i++) {
sources[i]->sel_score = 1.0;
sources[i]->outlier = 0;
}
}
sources[selected_source_index]->status = SRC_SYNC;
/* Update local reference only when a new source was selected or a new
sample was received (i.e. match_addr is equal to selected ref_id) */
sample was received (i.e. match_refid is equal to selected refid) */
if (selected_source_index != old_selected_index ||
match_addr == sources[selected_source_index]->ref_id) {
match_refid == sources[selected_source_index]->ref_id) {
/* Now just use the statistics of the selected source for
trimming the local clock */
/* Now just use the statistics of the selected source combined with
the other selectable sources for trimming the local clock */
SST_GetTrackingData(sources[selected_source_index]->stats, &ref_time,
&src_offset, &src_offset_sd,
&src_frequency, &src_skew,
&src_root_delay, &src_root_dispersion);
REF_SetReference(min_stratum, leap_status,
combined = combine_sources(n_sel_sources, &ref_time, &src_offset,
&src_offset_sd, &src_frequency, &src_skew);
REF_SetReference(sources[selected_source_index]->sel_info.stratum,
leap_status,
combined,
sources[selected_source_index]->ref_id,
sources[selected_source_index]->ip_addr,
&ref_time,
src_offset,
src_offset_sd,
src_frequency,
src_skew,
src_root_delay,
@@ -1101,12 +1196,29 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
report->state = RPT_FALSETICKER;
break;
case SRC_SELECTABLE:
report->state = RPT_CANDIDATE;
report->state = src->outlier ? RPT_OUTLIER : RPT_CANDIDATE;
break;
default:
assert(0);
break;
}
switch (src->sel_option) {
case SRC_SelectNormal:
report->sel_option = RPT_NOSELECT;
break;
case SRC_SelectPrefer:
report->sel_option = RPT_PREFER;
break;
case SRC_SelectNoselect:
report->sel_option = RPT_NOSELECT;
break;
default:
assert(0);
}
report->reachability = src->reachability;
/* Call stats module to fill out estimates */
SST_DoSourceReport(src->stats, report, now);

View File

@@ -61,7 +61,7 @@ typedef enum {
/* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */
extern SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr);
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr);
/* Function to get rid of a source when it is being unconfigured.
This may cause the current reference source to be reselected, if this
@@ -135,7 +135,7 @@ extern void SRC_ResetReachability(SRC_Instance inst);
reference source address. (This avoids updating the frequency
tracking for every sample from other sources - only the ones from
the selected reference make a difference) */
extern void SRC_SelectSource(unsigned long match_addr);
extern void SRC_SelectSource(uint32_t match_refid);
/* Force reselecting the best source */
extern void SRC_ReselectSource(void);

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011
* Copyright (C) Miroslav Lichvar 2011-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -26,6 +26,8 @@
analysis on the samples obtained from the sources,
to determined frequencies and error bounds. */
#include "config.h"
#include "sysincl.h"
#include "sourcestats.h"
@@ -41,10 +43,17 @@
to store per source */
#define MAX_SAMPLES 64
/* User defined maximum and minimum number of samples */
int max_samples;
int min_samples;
/* This is the assumed worst case bound on an unknown frequency,
2000ppm, which would be pretty bad */
#define WORST_CASE_FREQ_BOUND (2000.0/1.0e6)
/* The minimum allowed skew */
#define MIN_SKEW 1.0e-12
/* ================================================== */
static LOG_FileID logfileid;
@@ -56,7 +65,7 @@ static LOG_FileID logfileid;
struct SST_Stats_Record {
/* Reference ID and IP address of source, used for logging to statistics log */
unsigned long refid;
uint32_t refid;
IPAddr *ip_addr;
/* Number of samples currently stored. The samples are stored in circular
@@ -158,6 +167,8 @@ SST_Initialise(void)
logfileid = CNF_GetLogStatistics() ? LOG_FileOpen("statistics",
" Date (UTC) Time IP Address Std dev'n Est offset Offset sd Diff freq Est skew Stress Ns Bs Nr")
: -1;
max_samples = CNF_GetMaxSamples();
min_samples = CNF_GetMinSamples();
}
/* ================================================== */
@@ -171,7 +182,7 @@ SST_Finalise(void)
/* This function creates a new instance of the statistics handler */
SST_Stats
SST_CreateInstance(unsigned long refid, IPAddr *addr)
SST_CreateInstance(uint32_t refid, IPAddr *addr)
{
SST_Stats inst;
inst = MallocNew(struct SST_Stats_Record);
@@ -202,7 +213,6 @@ void
SST_DeleteInstance(SST_Stats inst)
{
Free(inst);
return;
}
/* ================================================== */
@@ -237,10 +247,20 @@ SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time,
{
int n, m;
if (inst->n_samples == MAX_SAMPLES) {
/* Make room for the new sample */
if (inst->n_samples > 0 &&
(inst->n_samples == MAX_SAMPLES || inst->n_samples == max_samples)) {
prune_register(inst, 1);
}
/* Make sure it's newer than the last sample */
if (inst->n_samples &&
UTI_CompareTimevals(&inst->sample_times[inst->last_sample], sample_time) >= 0) {
LOG(LOGS_WARN, LOGF_SourceStats, "Out of order sample detected, discarding history for %s",
inst->ip_addr ? UTI_IPToString(inst->ip_addr) : UTI_RefidToString(inst->refid));
prune_register(inst, inst->n_samples);
}
n = inst->last_sample = (inst->last_sample + 1) %
(MAX_SAMPLES * REGRESS_RUNS_RATIO);
m = n % MAX_SAMPLES;
@@ -248,7 +268,7 @@ SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time,
inst->sample_times[n] = *sample_time;
inst->offsets[n] = offset;
inst->orig_offsets[m] = offset;
inst->peer_delays[m] = fabs(peer_delay);
inst->peer_delays[m] = peer_delay;
inst->peer_dispersions[m] = peer_dispersion;
inst->root_delays[m] = root_delay;
inst->root_dispersions[m] = root_dispersion;
@@ -324,7 +344,7 @@ find_best_sample_index(SST_Stats inst, double *times_back)
elapsed = -times_back[i];
assert(elapsed >= 0.0);
root_distance = inst->root_dispersions[j] + elapsed * inst->skew + 0.5 * fabs(inst->root_delays[j]);
root_distance = inst->root_dispersions[j] + elapsed * inst->skew + 0.5 * inst->root_delays[j];
if (root_distance < best_root_distance) {
best_root_distance = root_distance;
best_index = i;
@@ -337,8 +357,6 @@ find_best_sample_index(SST_Stats inst, double *times_back)
#if 0
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d best_index=%d", n, best_index);
#endif
return;
}
/* ================================================== */
@@ -420,6 +438,7 @@ SST_DoNewRegression(SST_Stats inst)
inst->regression_ok = RGR_FindBestRegression(times_back + inst->runs_samples,
offsets + inst->runs_samples, weights,
inst->n_samples, inst->runs_samples,
min_samples,
&est_intercept, &est_slope, &est_var,
&est_intercept_sd, &est_slope_sd,
&best_start, &nruns, &degrees_of_freedom);
@@ -437,6 +456,9 @@ SST_DoNewRegression(SST_Stats inst)
inst->variance = est_var;
inst->nruns = nruns;
if (inst->skew < MIN_SKEW)
inst->skew = MIN_SKEW;
stress = fabs(old_freq - inst->estimated_frequency) / old_skew;
if (best_start > 0) {
@@ -480,38 +502,6 @@ SST_DoNewRegression(SST_Stats inst)
}
/* ================================================== */
void
SST_GetReferenceData(SST_Stats inst, struct timeval *now,
int *stratum, double *offset,
double *root_delay, double *root_dispersion,
double *frequency, double *skew)
{
double elapsed;
int i, j;
*frequency = inst->estimated_frequency;
*skew = inst->skew;
i = get_runsbuf_index(inst, inst->best_single_sample);
j = get_buf_index(inst, inst->best_single_sample);
UTI_DiffTimevalsToDouble(&elapsed, now, &inst->sample_times[i]);
*root_delay = inst->root_delays[j];
*root_dispersion = inst->root_dispersions[j] + elapsed * inst->skew;
*offset = inst->offsets[i] + elapsed * inst->estimated_frequency;
*stratum = inst->strata[j];
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d freq=%f skew=%f del=%f disp=%f ofs=%f str=%d",
inst->n_samples, *frequency, *skew, *root_delay, *root_dispersion, *offset, *stratum);
#endif
return;
}
/* ================================================== */
/* Return the assumed worst case range of values that this source's
frequency lies within. Frequency is defined as the amount of time
@@ -526,59 +516,63 @@ SST_GetFrequencyRange(SST_Stats inst,
skew = inst->skew;
*lo = freq - skew;
*hi = freq + skew;
}
/* ================================================== */
/* This function is currently used only to determine the values of delta
and epsilon in the ntp_core module. Limit the skew to a reasonable maximum
to avoid failing the dispersion test too easily. */
if (skew > WORST_CASE_FREQ_BOUND) {
*lo = -WORST_CASE_FREQ_BOUND;
*hi = WORST_CASE_FREQ_BOUND;
}
}
/* ================================================== */
void
SST_GetSelectionData(SST_Stats inst, struct timeval *now,
int *stratum,
double *best_offset, double *best_root_delay,
double *best_root_dispersion,
double *offset_lo_limit,
double *offset_hi_limit,
double *root_distance,
double *variance, int *select_ok)
{
double average_offset;
double sample_elapsed;
double elapsed;
double offset, sample_elapsed;
int i, j;
int average_ok;
double peer_distance;
i = get_runsbuf_index(inst, inst->best_single_sample);
j = get_buf_index(inst, inst->best_single_sample);
*stratum = inst->strata[j];
*stratum = inst->strata[get_buf_index(inst, inst->n_samples - 1)];
*variance = inst->variance;
peer_distance = inst->peer_dispersions[j] + 0.5 * inst->peer_delays[j];
UTI_DiffTimevalsToDouble(&elapsed, now, &(inst->offset_time));
UTI_DiffTimevalsToDouble(&sample_elapsed, now, &inst->sample_times[i]);
*best_offset = inst->offsets[i] + sample_elapsed * inst->estimated_frequency;
*best_root_delay = inst->root_delays[j];
*best_root_dispersion = inst->root_dispersions[j] + sample_elapsed * inst->skew;
offset = inst->offsets[i] + sample_elapsed * inst->estimated_frequency;
*root_distance = 0.5 * inst->root_delays[j] +
inst->root_dispersions[j] + sample_elapsed * inst->skew;
*offset_lo_limit = offset - *root_distance;
*offset_hi_limit = offset + *root_distance;
#if 0
double average_offset, elapsed;
int average_ok;
/* average_ok ignored for now */
UTI_DiffTimevalsToDouble(&elapsed, now, &(inst->offset_time));
average_offset = inst->estimated_offset + inst->estimated_frequency * elapsed;
if (fabs(average_offset - *best_offset) <= peer_distance) {
if (fabs(average_offset - offset) <=
inst->peer_dispersions[j] + 0.5 * inst->peer_delays[j]) {
average_ok = 1;
} else {
average_ok = 0;
}
#endif
*select_ok = inst->regression_ok;
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d off=%f del=%f dis=%f var=%f pdist=%f avoff=%f avok=%d selok=%d",
inst->n_samples, *best_offset, *best_root_delay, *best_root_dispersion, *variance,
peer_distance, average_offset, average_ok, *select_ok);
#else
(void)average_ok;
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d off=%f dist=%f var=%f selok=%d",
inst->n_samples, offset, *root_distance, *variance, *select_ok);
#endif
return;
}
/* ================================================== */
@@ -658,8 +652,6 @@ SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffs
#else
(void)prev; (void)prev_freq;
#endif
return;
}
/* ================================================== */

View File

@@ -38,7 +38,7 @@ extern void SST_Initialise(void);
extern void SST_Finalise(void);
/* This function creates a new instance of the statistics handler */
extern SST_Stats SST_CreateInstance(unsigned long refid, IPAddr *addr);
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr);
/* This function deletes an instance of the statistics handler. */
extern void SST_DeleteInstance(SST_Stats inst);
@@ -82,10 +82,10 @@ extern void SST_GetFrequencyRange(SST_Stats inst, double *lo, double *hi);
extern void
SST_GetSelectionData(SST_Stats inst, struct timeval *now,
int *stratum,
double *best_offset, double *best_root_delay,
double *best_root_dispersion,
double *variance,
int *select_ok);
double *offset_lo_limit,
double *offset_hi_limit,
double *root_distance,
double *variance, int *select_ok);
/* Get data needed when setting up tracking on this source */
extern void
@@ -94,15 +94,6 @@ SST_GetTrackingData(SST_Stats inst, struct timeval *ref_time,
double *frequency, double *skew,
double *root_delay, double *root_dispersion);
/* Get parameters for using this source as the reference */
extern void
SST_GetReferenceData(SST_Stats inst, struct timeval *now,
int *stratum, double *offset,
double *root_delay, double *root_dispersion,
double *frequency, double *skew);
/* This routine is called when the local machine clock parameters are
changed. It adjusts all existing samples that we are holding for
each peer so that it looks like they were made under the new clock

View File

@@ -50,7 +50,7 @@ typedef struct {
#define SRC_DEFAULT_MAXPOLL 10
#define SRC_DEFAULT_PRESEND_MINPOLL 0
#define SRC_DEFAULT_MAXDELAY 16.0
#define SRC_DEFAULT_MAXDELAYRATIO 16384.0
#define SRC_DEFAULT_MAXDELAYRATIO 0.0
#define SRC_DEFAULT_MAXDELAYDEVRATIO 10.0
#define SRC_DEFAULT_MINSTRATUM 0
#define SRC_DEFAULT_POLLTARGET 6

View File

@@ -24,6 +24,8 @@
Replacement strerror function for systems that don't have it
*/
#include "config.h"
#ifdef SUNOS
#include <errno.h>

10
sys.c
View File

@@ -25,6 +25,8 @@
in the various operating-system specific modules
*/
#include "config.h"
#include "sys.h"
#include "logging.h"
@@ -89,8 +91,6 @@ SYS_Finalise(void)
#if defined(__NetBSD__)
SYS_NetBSD_Finalise();
#endif
return;
}
/* ================================================== */
@@ -102,8 +102,6 @@ void SYS_DropRoot(char *user)
#else
LOG_FATAL(LOGF_Sys, "dropping root privileges not supported");
#endif
return;
}
/* ================================================== */
@@ -115,8 +113,6 @@ void SYS_SetScheduler(int SchedPriority)
#else
LOG_FATAL(LOGF_Sys, "scheduler priority setting not supported");
#endif
return;
}
/* ================================================== */
@@ -128,8 +124,6 @@ void SYS_LockMemory(void)
#else
LOG_FATAL(LOGF_Sys, "memory locking not supported");
#endif
return;
}
/* ================================================== */

View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2009-2011
* Copyright (C) Miroslav Lichvar 2009-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -27,14 +27,10 @@
*/
#ifdef LINUX
#include "config.h"
#include "sysincl.h"
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <ctype.h>
#include <assert.h>
#include <sys/utsname.h>
#if defined(HAVE_SCHED_SETSCHEDULER)
@@ -104,8 +100,7 @@ static int version_patchlevel;
/* Flag indicating whether adjtimex() returns the remaining time adjustment
or not. If not we have to read the outstanding adjustment by setting it to
zero, examining the return value and setting the outstanding adjustment back
again. If 1, txc.modes equal to zero is used to read the time. If 2,
txc.modes is set to ADJ_OFFSET_SS_READ. */
again. */
static int have_readonly_adjtime;
@@ -114,6 +109,9 @@ static int have_readonly_adjtime;
adjustments. */
static int have_nanopll;
/* Flag indicating whether adjtimex() can step the clock */
static int have_setoffset;
/* ================================================== */
static void handle_end_of_slew(void *anything);
@@ -170,6 +168,9 @@ static SCH_TimeoutID slew_timeout_id;
a fast slew */
static double delta_total_tick;
/* Maximum length of one fast slew */
#define MAX_FASTSLEW_TIMEOUT (3600 * 24 * 7)
/* Max amount of time that we wish to slew by using adjtime (or its
equivalent). If more than this is outstanding, we alter the value
of tick instead, for a set period. Set this according to the
@@ -178,7 +179,7 @@ static double delta_total_tick;
#define MAX_ADJUST_WITH_ADJTIME (0.2)
/* Max amount of time that should be adjusted by kernel PLL */
#define MAX_ADJUST_WITH_NANOPLL (1.0e-5)
#define MAX_ADJUST_WITH_NANOPLL (0.5)
/* The amount by which we alter 'tick' when doing a large slew */
static int slew_delta_tick;
@@ -205,6 +206,18 @@ static double fast_slew_error;
/* The rate at which frequency and tick values are updated in kernel. */
static int tick_update_hz;
#define MIN_PLL_TIME_CONSTANT 0
#define MAX_PLL_TIME_CONSTANT 10
/* PLL time constant used when adjusting offset by PLL */
static long pll_time_constant;
/* Suggested offset correction rate (correction time * offset) */
static double correction_rate;
/* Kernel time constant shift */
static int shift_pll;
/* ================================================== */
/* These routines are used to estimate maximum error in offset correction */
@@ -265,9 +278,8 @@ update_nano_slew_error(long offset, int new)
if (offset == 0 && nano_slew_error == 0)
return;
/* maximum error in offset reported by adjtimex, assuming PLL constant 0
and SHIFT_PLL = 2 */
offset /= new ? 4 : 3;
/* maximum error in offset reported by adjtimex */
offset /= (1 << (shift_pll + pll_time_constant)) - (new ? 0 : 1);
if (offset < 0)
offset = -offset;
@@ -336,6 +348,27 @@ get_fast_slew_error(struct timeval *now)
return left > 0.0 ? fast_slew_error : 0.0;
}
/* ================================================== */
/* Select PLL time constant according to the suggested correction rate. */
static long
get_pll_constant(double offset)
{
long c;
double corr_time;
if (offset < 1e-9)
return MIN_PLL_TIME_CONSTANT;
corr_time = correction_rate / offset;
for (c = MIN_PLL_TIME_CONSTANT; c < MAX_PLL_TIME_CONSTANT; c++)
if (corr_time < 1 << (c + 1 + shift_pll))
break;
return c;
}
/* ================================================== */
/* This routine stops a fast slew, determines how long the slew has
been running for, and consequently how much adjustment has actually
@@ -380,7 +413,8 @@ stop_fast_slew(void)
}
/* ================================================== */
/* This routine reschedules fast slew timeout after frequency was changed */
/* This routine reschedules fast slew timeout according
to the current frequency and offset */
static void
adjust_fast_slew(double old_tick, double old_delta_tick)
@@ -401,8 +435,8 @@ adjust_fast_slew(double old_tick, double old_delta_tick)
dseconds = -offset_register * (current_total_tick + delta_total_tick) / delta_total_tick;
if (dseconds > 3600 * 24 * 7)
dseconds = 3600 * 24 * 7;
if (dseconds > MAX_FASTSLEW_TIMEOUT)
dseconds = MAX_FASTSLEW_TIMEOUT;
UTI_AddDoubleToTimeval(&tv, dseconds, &end_of_slew);
slew_start_tv = tv;
@@ -449,7 +483,7 @@ initiate_slew(void)
update_nano_slew_error(offset, 0);
offset = 0;
if (TMX_ApplyPLLOffset(offset) < 0) {
if (TMX_ApplyPLLOffset(offset, MIN_PLL_TIME_CONSTANT) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
nano_slewing = 0;
@@ -457,13 +491,23 @@ initiate_slew(void)
}
if (have_nanopll && fabs(offset_register) < MAX_ADJUST_WITH_NANOPLL) {
/* Use PLL with fixed frequency to do the shift */
/* Use the PLL with fixed frequency to do the shift. Until the kernel has a
support for linear offset adjustments with programmable rate this is the
best we can do. */
offset = 1.0e9 * -offset_register;
if (TMX_ApplyPLLOffset(offset) < 0) {
/* First adjustment after accrue_offset() sets the PLL time constant */
if (pll_time_constant < 0) {
pll_time_constant = get_pll_constant(fabs(offset_register));
}
assert(pll_time_constant >= MIN_PLL_TIME_CONSTANT &&
pll_time_constant <= MAX_PLL_TIME_CONSTANT);
if (TMX_ApplyPLLOffset(offset, pll_time_constant) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
offset_register = 0.0;
offset_register = 0.0; /* Don't keep the sub-nanosecond leftover */
nano_slewing = 1;
update_nano_slew_error(offset, 1);
} else if (fabs(offset_register) < MAX_ADJUST_WITH_ADJTIME) {
@@ -538,9 +582,8 @@ initiate_slew(void)
fast_slewing = 1;
slew_start_tv = T0;
/* Set up timeout for end of slew, limit to one week */
if (dseconds > 3600 * 24 * 7)
dseconds = 3600 * 24 * 7;
if (dseconds > MAX_FASTSLEW_TIMEOUT)
dseconds = MAX_FASTSLEW_TIMEOUT;
UTI_AddDoubleToTimeval(&T0, dseconds, &end_of_slew);
slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
@@ -549,8 +592,6 @@ initiate_slew(void)
offset_register = 0.0;
}
return;
}
/* ================================================== */
@@ -586,16 +627,21 @@ abort_slew(void)
time) */
static void
accrue_offset(double offset)
accrue_offset(double offset, double corr_rate)
{
/* Add the new offset to the register */
offset_register += offset;
correction_rate = corr_rate;
/* Select a new time constant on the next adjustment */
pll_time_constant = -1;
if (!fast_slewing) {
initiate_slew();
} /* Otherwise, when the fast slew completes, any other stuff
in the offset register will be applied */
} else {
adjust_fast_slew(current_total_tick, delta_total_tick);
}
}
/* ================================================== */
@@ -611,23 +657,29 @@ apply_step_offset(double offset)
abort_slew();
}
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
if (have_setoffset) {
if (TMX_ApplyStepOffset(-offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
} else {
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "settimeofday() failed");
}
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&err, &old_time, &new_time);
lcl_InvokeDispersionNotifyHandlers(fabs(err));
}
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "settimeofday() failed");
}
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&err, &old_time, &new_time);
lcl_InvokeDispersionNotifyHandlers(fabs(err));
initiate_slew();
}
@@ -648,29 +700,11 @@ set_frequency(double freq_ppm)
double scaled_freq; /* what adjtimex & the kernel use */
double old_total_tick;
int required_delta_tick;
int neg; /* True if estimate is that local clock runs slow,
i.e. positive frequency correction required */
if (freq_ppm < 0.0) {
neg = 1;
freq_ppm = -freq_ppm;
} else {
neg = 0;
}
required_delta_tick = our_round(freq_ppm / dhz);
required_freq = freq_ppm - dhz * (double) required_delta_tick;
if (neg) {
/* Uncompensated local clock runs slow */
required_tick = nominal_tick + required_delta_tick;
scaled_freq = freq_scale * required_freq;
} else {
/* Uncompensated local clock runs fast */
required_tick = nominal_tick - required_delta_tick;
scaled_freq = -freq_scale * required_freq;
}
required_freq = -(freq_ppm - dhz * required_delta_tick);
required_tick = nominal_tick - required_delta_tick;
scaled_freq = freq_scale * required_freq;
min_allowed_tick = nominal_tick - max_tick_bias;
max_allowed_tick = nominal_tick + max_tick_bias;
@@ -719,15 +753,17 @@ read_frequency(void)
double tick_term;
double unscaled_freq;
double freq_term;
long tick;
if (TMX_GetFrequency(&unscaled_freq) < 0) {
if (TMX_GetFrequency(&unscaled_freq, &tick) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
/* Use current_tick here rather than txc.tick, otherwise we're
thrown off course when doing a fast slew (in which case, txc.tick
is nowhere near the nominal value) */
tick_term = dhz * (double)(nominal_tick - current_tick);
if (fast_slewing) {
tick -= slewing_tick - current_tick;
}
tick_term = dhz * (double)(nominal_tick - tick);
freq_term = unscaled_freq / freq_scale;
#if 0
@@ -764,29 +800,19 @@ get_offset_correction(struct timeval *raw,
if (!slow_slewing) {
offset = 0;
} else {
switch (have_readonly_adjtime) {
case 2:
if (TMX_GetOffsetLeft(&offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
break;
case 0:
toffset = 0;
if (TMX_ApplyOffset(&toffset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
offset = toffset;
if (TMX_ApplyOffset(&toffset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
break;
case 1:
if (TMX_GetOffsetLeftOld(&offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
break;
default:
assert(0);
if (have_readonly_adjtime) {
if (TMX_GetOffsetLeft(&offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
} else {
toffset = 0;
if (TMX_ApplyOffset(&toffset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
offset = toffset;
if (TMX_ApplyOffset(&toffset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
}
if (offset == 0) {
@@ -822,8 +848,6 @@ get_offset_correction(struct timeval *raw,
update_nano_slew_error(noffset, 0);
*err = get_slow_slew_error(raw) + get_fast_slew_error(raw) + get_nano_slew_error();;
}
return;
}
/* ================================================== */
@@ -837,8 +861,6 @@ set_leap(int leap)
LOG(LOGS_INFO, LOGF_SysLinux, "System clock status set to %s leap second",
leap ? (leap > 0 ? "insert" : "delete") : "not insert/delete");
return;
}
/* ================================================== */
@@ -876,7 +898,43 @@ guess_hz_and_shift_hz(int tick, int *hz, int *shift_hz)
/* oh dear. doomed. */
*hz = 0;
*shift_hz = 0;
return;
}
/* ================================================== */
static int
get_hz_and_shift_hz(int *hz, int *shift_hz)
{
#ifdef _SC_CLK_TCK
if ((*hz = sysconf(_SC_CLK_TCK)) < 1) {
return 0;
}
if (*hz == 100) {
*shift_hz = 7;
return 1;
}
for (*shift_hz = 1; (*hz >> *shift_hz) > 1; (*shift_hz)++)
;
return 1;
#else
return 0;
#endif
}
/* ================================================== */
static int
kernelvercmp(int major1, int minor1, int patch1,
int major2, int minor2, int patch2)
{
if (major1 != major2)
return major1 - major2;
if (minor1 != minor2)
return minor1 - minor2;
return patch1 - patch2;
}
/* ================================================== */
@@ -893,22 +951,23 @@ get_version_specific_details(void)
int config_hz, set_config_hz; /* values of HZ from conf file */
int set_config_freq_scale;
double config_freq_scale;
double calculated_freq_scale;
struct tmx_params tmx_params;
struct utsname uts;
TMX_ReadCurrentParams(&tmx_params);
guess_hz_and_shift_hz(tmx_params.tick, &hz, &shift_hz);
if (!get_hz_and_shift_hz(&hz, &shift_hz)) {
TMX_ReadCurrentParams(&tmx_params);
if (!shift_hz) {
LOG_FATAL(LOGF_SysLinux, "Can't determine hz (txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld)",
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset);
} else {
guess_hz_and_shift_hz(tmx_params.tick, &hz, &shift_hz);
if (!shift_hz) {
LOG_FATAL(LOGF_SysLinux, "Can't determine hz (txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld)",
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset);
} else {
#if 0
LOG(LOGS_INFO, LOGF_SysLinux, "Initial txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld => hz=%d shift_hz=%d",
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset, hz, shift_hz);
LOG(LOGS_INFO, LOGF_SysLinux, "Initial txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld => hz=%d shift_hz=%d",
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset, hz, shift_hz);
#endif
}
}
CNF_GetLinuxHz(&set_config_hz, &config_hz);
@@ -924,10 +983,6 @@ get_version_specific_details(void)
max_tick_bias = nominal_tick / 10;
tick_update_hz = hz;
LOG(LOGS_INFO, LOGF_SysLinux, "set_config_hz=%d hz=%d shift_hz=%d basic_freq_scale=%.8f nominal_tick=%d slew_delta_tick=%d max_tick_bias=%d",
set_config_hz, hz, shift_hz, basic_freq_scale, nominal_tick, slew_delta_tick, max_tick_bias);
/* The basic_freq_scale comes from:
* the kernel increments the usec counter HZ times per second (if the timer
interrupt period were perfect)
@@ -958,7 +1013,9 @@ get_version_specific_details(void)
if (uname(&uts) < 0) {
LOG_FATAL(LOGF_SysLinux, "Cannot uname(2) to get kernel version, sorry.");
}
if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) != 3) {
patch = 0;
if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) < 2) {
LOG_FATAL(LOGF_SysLinux, "Cannot read information from uname, sorry");
}
@@ -968,102 +1025,60 @@ get_version_specific_details(void)
version_minor = minor;
version_patchlevel = patch;
have_nanopll = 0;
switch (major) {
case 1:
/* Does Linux v1.x even support HZ!=100? */
switch (minor) {
case 2:
if (patch == 13) {
freq_scale = (hz==100) ? (128.0 / 100.0) : basic_freq_scale ; /* I _think_! */
have_readonly_adjtime = 1;
} else {
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
}
break;
case 3:
/* I guess the change from the 1.2.x scaling to the 2.0.x
scaling must have happened during 1.3 development. I
haven't a clue where though, until someone looks it
up. */
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
break;
default:
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
break;
}
break;
case 2:
switch (minor) {
case 0:
if (patch < 32) {
freq_scale = (hz==100) ? (128.0 / 125.0) : basic_freq_scale;
have_readonly_adjtime = 1;
} else if (patch >= 32) {
freq_scale = (hz==100) ? (128.0 / 128.125) : basic_freq_scale;
/* The functionality in kernel/time.c in the kernel source
was modified with regard to what comes back in the
txc.offset field on return from adjtimex. If txc.modes
was ADJ_OFFSET_SINGLESHOT on entry, the outstanding
adjustment is returned, however the running offset will
be modified to the passed value. */
have_readonly_adjtime = 0;
}
break;
case 1:
/* I know that earlier 2.1 kernels were like 2.0.31, hence
the settings below. However, the 2.0.32 behaviour may
have been added late in the 2.1 series, however I have no
idea at which patch level. Leave it like this until
someone supplies some info. */
freq_scale = (hz==100) ? (128.0 / 125.0) : basic_freq_scale;
have_readonly_adjtime = 0; /* For safety ! */
break;
case 2:
case 3:
case 4:
case 5:
case 6:
if (minor < 6 || patch < 27) {
/* These seem to be like 2.0.32 */
freq_scale = (hz==100) ? (128.0 / 128.125) : basic_freq_scale;
have_readonly_adjtime = 0;
break;
}
if (patch < 33) {
/* Tickless kernels before 2.6.33 accumulated ticks only in
half-second intervals. */
tick_update_hz = 2;
}
/* Let's be optimistic that these will be the same until proven
otherwise :-) */
case 7:
case 8:
/* These don't seem to need scaling */
freq_scale = 1.0;
have_readonly_adjtime = 2;
have_nanopll = 1;
break;
default:
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
}
break;
default:
LOG_FATAL(LOGF_SysLinux, "Kernel's major version not supported yet, sorry");
break;
if (kernelvercmp(major, minor, patch, 2, 2, 0) < 0) {
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported, sorry.");
}
if (kernelvercmp(major, minor, patch, 2, 6, 27) < 0) {
freq_scale = (hz == 100) ? (128.0 / 128.125) : basic_freq_scale;
} else {
/* These don't seem to need scaling */
freq_scale = 1.0;
if (kernelvercmp(major, minor, patch, 2, 6, 33) < 0) {
/* Tickless kernels before 2.6.33 accumulated ticks only in
half-second intervals */
tick_update_hz = 2;
}
}
/* ADJ_OFFSET_SS_READ support. It's available since 2.6.24,
but was buggy until 2.6.28. */
if (kernelvercmp(major, minor, patch, 2, 6, 28) < 0) {
have_readonly_adjtime = 0;
} else {
have_readonly_adjtime = 1;
}
/* ADJ_NANO support */
if (kernelvercmp(major, minor, patch, 2, 6, 27) < 0) {
have_nanopll = 0;
} else {
have_nanopll = 1;
}
/* ADJ_SETOFFSET support */
if (kernelvercmp(major, minor, patch, 2, 6, 39) < 0) {
have_setoffset = 0;
} else {
have_setoffset = 1;
}
/* PLL time constant changed in 2.6.31 */
if (kernelvercmp(major, minor, patch, 2, 6, 31) < 0) {
shift_pll = 4;
} else {
shift_pll = 2;
}
/* Override freq_scale if it appears in conf file */
CNF_GetLinuxFreqScale(&set_config_freq_scale, &config_freq_scale);
calculated_freq_scale = freq_scale;
if (set_config_freq_scale) {
freq_scale = config_freq_scale;
LOG(LOGS_INFO, LOGF_SysLinux, "calculated_freq_scale=%.8f freq_scale=%.8f",
calculated_freq_scale, freq_scale);
}
LOG(LOGS_INFO, LOGF_SysLinux, "hz=%d shift_hz=%d freq_scale=%.8f nominal_tick=%d slew_delta_tick=%d max_tick_bias=%d shift_pll=%d",
hz, shift_hz, freq_scale, nominal_tick, slew_delta_tick, max_tick_bias, shift_pll);
}
/* ================================================== */
@@ -1073,25 +1088,19 @@ void
SYS_Linux_Initialise(void)
{
long offset;
double freq;
offset_register = 0.0;
fast_slewing = 0;
get_version_specific_details();
current_tick = nominal_tick;
current_total_tick = 1.0 / dhz;
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
get_offset_correction, set_leap);
offset = 0;
if (TMX_ApplyOffset(&offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
if (have_readonly_adjtime == 2 && (TMX_GetOffsetLeft(&offset) < 0 || offset)) {
if (have_readonly_adjtime && (TMX_GetOffsetLeft(&offset) < 0 || offset)) {
LOG(LOGS_INFO, LOGF_SysLinux, "adjtimex() doesn't support ADJ_OFFSET_SS_READ");
have_readonly_adjtime = 0;
}
@@ -1101,7 +1110,20 @@ SYS_Linux_Initialise(void)
have_nanopll = 0;
}
if (have_setoffset && TMX_TestStepOffset() < 0) {
LOG(LOGS_INFO, LOGF_SysLinux, "adjtimex() doesn't support ADJ_SETOFFSET");
have_setoffset = 0;
}
TMX_SetSync(CNF_GetRTCSync());
/* Read current kernel frequency */
TMX_GetFrequency(&freq, &current_tick);
current_total_tick = (current_tick + freq / freq_scale / dhz) / 1.0e6;
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
get_offset_correction, set_leap);
}
/* ================================================== */
@@ -1117,16 +1139,6 @@ SYS_Linux_Finalise(void)
/* ================================================== */
void
SYS_Linux_GetKernelVersion(int *major, int *minor, int *patchlevel)
{
*major = version_major;
*minor = version_minor;
*patchlevel = version_patchlevel;
}
/* ================================================== */
#ifdef FEAT_LINUXCAPS
void
SYS_Linux_DropRoot(char *user)
@@ -1232,9 +1244,3 @@ void SYS_Linux_MemLockAll(int LockAll)
}
}
#endif /* HAVE_MLOCKALL */
#endif /* LINUX */
/* vim:ts=8
* */

View File

@@ -31,8 +31,6 @@ extern void SYS_Linux_Initialise(void);
extern void SYS_Linux_Finalise(void);
extern void SYS_Linux_GetKernelVersion(int *major, int *minor, int *patchlevel);
extern void SYS_Linux_DropRoot(char *user);
extern void SYS_Linux_MemLockAll(int LockAll);

View File

@@ -25,6 +25,8 @@
Driver file for the NetBSD operating system.
*/
#include "config.h"
#ifdef __NetBSD__
#include <kvm.h>
@@ -197,7 +199,7 @@ stop_adjust(void)
slew backwards */
static void
accrue_offset(double offset)
accrue_offset(double offset, double corr_rate)
{
stop_adjust();
offset_register += offset;

View File

@@ -24,6 +24,8 @@
Driver file for Solaris operating system
*/
#include "config.h"
#ifdef SOLARIS
#include <kvm.h>
@@ -108,8 +110,6 @@ clock_initialise(void)
if (adjtime(&newadj, &oldadj) < 0) {
LOG_FATAL(LOGF_SysSolaris, "adjtime() failed");
}
return;
}
/* ================================================== */
@@ -118,9 +118,6 @@ static void
clock_finalise(void)
{
/* Nothing to do yet */
return;
}
/* ================================================== */
@@ -210,12 +207,11 @@ stop_adjust(void)
slew backwards */
static void
accrue_offset(double offset)
accrue_offset(double offset, double corr_rate)
{
stop_adjust();
offset_register += offset;
start_adjust();
return;
}
/* ================================================== */
@@ -294,7 +290,6 @@ get_offset_correction(struct timeval *raw,
start_adjust();
if (err)
*err = 0.0;
return;
}
/* ================================================== */
@@ -302,7 +297,6 @@ get_offset_correction(struct timeval *raw,
static void
immediate_step(void)
{
return;
}
/* ================================================== */
@@ -466,8 +460,6 @@ SYS_Solaris_Finalise(void)
if (need_dosynctodr) {
set_dosynctodr(1);
}
return;
}
/* ================================================== */

View File

@@ -24,6 +24,8 @@
Driver file for the SunOS 4.1.x operating system.
*/
#include "config.h"
#ifdef SUNOS
#include <kvm.h>
@@ -99,8 +101,6 @@ clock_initialise(void)
if (adjtime(&newadj, &oldadj) < 0) {
LOG_FATAL(LOGF_SysSunOS, "adjtime() failed");
}
return;
}
/* ================================================== */
@@ -109,9 +109,6 @@ static void
clock_finalise(void)
{
/* Nothing to do yet */
return;
}
/* ================================================== */
@@ -214,12 +211,11 @@ stop_adjust(void)
slew backwards */
static void
accrue_offset(double offset)
accrue_offset(double offset, double corr_rate)
{
stop_adjust();
offset_register += offset;
start_adjust();
return;
}
/* ================================================== */
@@ -281,7 +277,6 @@ get_offset_correction(struct timeval *raw,
start_adjust();
if (err)
*err = 0.0;
return;
}
/* ================================================== */
@@ -289,7 +284,6 @@ get_offset_correction(struct timeval *raw,
static void
immediate_step(void)
{
return;
}
/* ================================================== */
@@ -418,8 +412,6 @@ SYS_SunOS_Finalise(void)
/* When exiting, we want to return the machine to its 'autonomous'
tracking mode */
setup_kernel(1);
return;
}
/* ================================================== */

View File

@@ -45,6 +45,7 @@
#include <math.h>
#include <netdb.h>
#include <netinet/in.h>
#include <resolv.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
@@ -56,6 +57,8 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/shm.h>
#include <syslog.h>
#include <time.h>
@@ -86,10 +89,6 @@
#include <nlist.h>
#endif
#if defined (HAS_NO_BZERO)
#define bzero(ptr,n) memset(ptr,0,n)
#endif /* HAS_NO_BZERO */
#if defined (WINNT)
/* Designed to work with the GCC from the GNAT-3.10 for Win32

View File

@@ -25,6 +25,8 @@
*/
#include "config.h"
#include "conf.h"
#include "local.h"
#include "memory.h"

155
util.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009, 2012-2013
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -25,10 +25,12 @@
Various utility functions
*/
#include "config.h"
#include "sysincl.h"
#include "util.h"
#include "md5.h"
#include "hash.h"
/* ================================================== */
@@ -105,8 +107,6 @@ UTI_DiffTimevals(struct timeval *result,
(0,1000000) */
UTI_NormaliseTimeval(result); /* JGH */
return;
}
/* ================================================== */
@@ -135,7 +135,8 @@ UTI_AddDoubleToTimeval(struct timeval *start,
is too marginal here. */
int_part = (long) increment;
frac_part = (long) (0.5 + 1.0e6 * (increment - (double)int_part));
increment = (increment - int_part) * 1.0e6;
frac_part = (long) (increment > 0.0 ? increment + 0.5 : increment - 0.5);
end->tv_sec = int_part + start->tv_sec;
end->tv_usec = frac_part + start->tv_usec;
@@ -187,6 +188,18 @@ UTI_AverageDiffTimevals (struct timeval *earlier,
/* ================================================== */
void
UTI_AddDiffToTimeval(struct timeval *a, struct timeval *b,
struct timeval *c, struct timeval *result)
{
double diff;
UTI_DiffTimevalsToDouble(&diff, a, b);
UTI_AddDoubleToTimeval(c, diff, result);
}
/* ================================================== */
#define POOL_ENTRIES 16
#define BUFFER_LENGTH 64
static char buffer_pool[POOL_ENTRIES][BUFFER_LENGTH];
@@ -210,19 +223,6 @@ UTI_TimevalToString(struct timeval *tv)
return result;
}
/* ================================================== */
#define JAN_1970 0x83aa7e80UL
inline static void
int64_to_timeval(NTP_int64 *src,
struct timeval *dest)
{
dest->tv_sec = ntohl(src->hi) - JAN_1970;
/* Until I invent a slick way to do this, just do it the obvious way */
dest->tv_usec = (int)(0.5 + (double)(ntohl(src->lo)) / 4294.967296);
}
/* ================================================== */
/* Convert an NTP timestamp into a temporary string, largely
for diagnostic display */
@@ -231,14 +231,14 @@ char *
UTI_TimestampToString(NTP_int64 *ts)
{
struct timeval tv;
int64_to_timeval(ts, &tv);
UTI_Int64ToTimeval(ts, &tv);
return UTI_TimevalToString(&tv);
}
/* ================================================== */
char *
UTI_RefidToString(unsigned long ref_id)
UTI_RefidToString(uint32_t ref_id)
{
unsigned int i, j, c;
char buf[5], *result;
@@ -331,19 +331,27 @@ UTI_StringToIP(const char *addr, IPAddr *ip)
/* ================================================== */
unsigned long
uint32_t
UTI_IPToRefid(IPAddr *ip)
{
MD5_CTX ctx;
static int MD5_hash = -1;
unsigned char buf[16];
switch (ip->family) {
case IPADDR_INET4:
return ip->addr.in4;
case IPADDR_INET6:
MD5Init(&ctx);
MD5Update(&ctx, (unsigned const char *) ip->addr.in6, sizeof (ip->addr.in6));
MD5Final(&ctx);
return ctx.digest[0] << 24 | ctx.digest[1] << 16 | ctx.digest[2] << 8 | ctx.digest[3];
if (MD5_hash < 0) {
MD5_hash = HSH_GetHashId("MD5");
assert(MD5_hash >= 0);
}
if (HSH_Hash(MD5_hash, (unsigned const char *)ip->addr.in6, sizeof
(ip->addr.in6), NULL, 0, buf, 16) != 16) {
assert(0);
return 0;
};
return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
}
return 0;
}
@@ -449,16 +457,53 @@ UTI_AdjustTimeval(struct timeval *old_tv, struct timeval *when, struct timeval *
/* ================================================== */
uint32_t
UTI_GetNTPTsFuzz(int precision)
{
uint32_t fuzz;
int fuzz_bits;
fuzz_bits = 32 - 1 + precision;
fuzz = random() % (1 << fuzz_bits);
return fuzz;
}
/* ================================================== */
double
UTI_Int32ToDouble(NTP_int32 x)
{
return (double) ntohl(x) / 65536.0;
}
/* ================================================== */
#define MAX_NTP_INT32 (4294967295.0 / 65536.0)
NTP_int32
UTI_DoubleToInt32(double x)
{
if (x > MAX_NTP_INT32)
x = MAX_NTP_INT32;
else if (x < 0)
x = 0.0;
return htonl((NTP_int32)(0.5 + 65536.0 * x));
}
/* ================================================== */
/* Seconds part of RFC1305 timestamp correponding to the origin of the
struct timeval format. */
#define JAN_1970 0x83aa7e80UL
void
UTI_TimevalToInt64(struct timeval *src,
NTP_int64 *dest)
NTP_int64 *dest, uint32_t fuzz)
{
unsigned long usec = src->tv_usec;
unsigned long sec = src->tv_sec;
uint32_t lo;
/* Recognize zero as a special case - it always signifies
an 'unknown' value */
@@ -468,7 +513,12 @@ UTI_TimevalToInt64(struct timeval *src,
dest->hi = htonl(src->tv_sec + JAN_1970);
/* This formula gives an error of about 0.1us worst case */
dest->lo = htonl(4295 * usec - (usec>>5) - (usec>>9));
lo = 4295 * usec - (usec>>5) - (usec>>9);
/* Add the fuzz */
lo ^= fuzz;
dest->lo = htonl(lo);
}
}
@@ -610,3 +660,52 @@ UTI_FdSetCloexec(int fd)
}
/* ================================================== */
int
UTI_GenerateNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, unsigned char *auth, int auth_len)
{
return HSH_Hash(hash_id, key, key_len, data, data_len, auth, auth_len);
}
/* ================================================== */
int
UTI_CheckNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, const unsigned char *auth, int auth_len)
{
unsigned char buf[MAX_HASH_LENGTH];
return UTI_GenerateNTPAuth(hash_id, key, key_len, data, data_len,
buf, sizeof (buf)) == auth_len && !memcmp(buf, auth, auth_len);
}
/* ================================================== */
int
UTI_DecodePasswordFromText(char *key)
{
int i, j, len = strlen(key);
char buf[3], *p;
if (!strncmp(key, "ASCII:", 6)) {
memmove(key, key + 6, len - 6);
return len - 6;
} else if (!strncmp(key, "HEX:", 4)) {
if ((len - 4) % 2)
return 0;
for (i = 0, j = 4; j + 1 < len; i++, j += 2) {
buf[0] = key[j], buf[1] = key[j + 1], buf[2] = '\0';
key[i] = strtol(buf, &p, 16);
if (p != buf + 2)
return 0;
}
return i;
} else {
/* assume ASCII */
return len;
}
}

23
util.h
View File

@@ -32,6 +32,7 @@
#include "addressing.h"
#include "ntp.h"
#include "candm.h"
#include "hash.h"
/* Convert a timeval into a floating point number of seconds */
extern void UTI_TimevalToDouble(struct timeval *a, double *b);
@@ -62,6 +63,9 @@ extern void UTI_AddDoubleToTimeval(struct timeval *start, double increment, stru
/* Calculate the average and difference (as a double) of two timevals */
extern void UTI_AverageDiffTimevals(struct timeval *earlier, struct timeval *later, struct timeval *average, double *diff);
/* Calculate result = a - b + c */
extern void UTI_AddDiffToTimeval(struct timeval *a, struct timeval *b, struct timeval *c, struct timeval *result);
/* Convert a timeval into a temporary string, largely for diagnostic
display */
extern char *UTI_TimevalToString(struct timeval *tv);
@@ -71,13 +75,13 @@ extern char *UTI_TimevalToString(struct timeval *tv);
extern char *UTI_TimestampToString(NTP_int64 *ts);
/* Convert ref_id into a temporary string, for diagnostics */
extern char *UTI_RefidToString(unsigned long ref_id);
extern char *UTI_RefidToString(uint32_t ref_id);
/* Convert an IP address to string, for diagnostics */
extern char *UTI_IPToString(IPAddr *ip);
extern int UTI_StringToIP(const char *addr, IPAddr *ip);
extern unsigned long UTI_IPToRefid(IPAddr *ip);
extern uint32_t UTI_IPToRefid(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);
@@ -87,8 +91,13 @@ extern char *UTI_TimeToLogForm(time_t t);
/* Adjust time following a frequency/offset change */
extern void UTI_AdjustTimeval(struct timeval *old_tv, struct timeval *when, struct timeval *new_tv, double *delta, double dfreq, double doffset);
/* Get a random value to fuzz an NTP timestamp in the given precision */
extern uint32_t UTI_GetNTPTsFuzz(int precision);
extern void UTI_TimevalToInt64(struct timeval *src, NTP_int64 *dest);
extern double UTI_Int32ToDouble(NTP_int32 x);
extern NTP_int32 UTI_DoubleToInt32(double x);
extern void UTI_TimevalToInt64(struct timeval *src, NTP_int64 *dest, uint32_t fuzz);
extern void UTI_Int64ToTimeval(NTP_int64 *src, struct timeval *dest);
@@ -101,6 +110,14 @@ extern Float UTI_FloatHostToNetwork(double x);
/* Set FD_CLOEXEC on descriptor */
extern void UTI_FdSetCloexec(int fd);
extern int UTI_GenerateNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, unsigned char *auth, int auth_len);
extern int UTI_CheckNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, const unsigned char *auth, int auth_len);
/* Decode password encoded in ASCII or HEX */
extern int UTI_DecodePasswordFromText(char *key);
#if defined (INLINE_UTILITIES)
#define INLINE_STATIC inline static
#include "util.c"

View File

@@ -1 +0,0 @@
DEVELOPMENT

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2011
* Copyright (C) Miroslav Lichvar 2011-2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -29,9 +29,7 @@
*/
#ifdef LINUX
#define _LOOSE_KERNEL_NAMES
#include "config.h"
#include "chrony_timex.h"
#include "wrap_adjtimex.h"
@@ -84,24 +82,14 @@ TMX_SetFrequency(double *freq, long tick)
}
int
TMX_GetFrequency(double *freq)
TMX_GetFrequency(double *freq, long *tick)
{
struct timex txc;
int result;
txc.modes = 0; /* pure read */
result = adjtimex(&txc);
*freq = txc.freq / (double)(1 << SHIFT_USEC);
return result;
}
int
TMX_GetOffsetLeftOld(long *offset)
{
struct timex txc;
int result;
txc.modes = 0; /* pure read */
result = adjtimex(&txc);
*offset = txc.offset;
*tick = txc.tick;
return result;
}
@@ -215,13 +203,13 @@ TMX_EnableNanoPLL(void)
}
int
TMX_ApplyPLLOffset(long offset)
TMX_ApplyPLLOffset(long offset, long constant)
{
struct timex txc;
txc.modes = ADJ_OFFSET | ADJ_TIMECONST | ADJ_NANO;
txc.offset = offset;
txc.constant = 0;
txc.constant = constant;
return adjtimex(&txc);
}
@@ -237,5 +225,50 @@ TMX_GetPLLOffsetLeft(long *offset)
return result;
}
#endif
int
TMX_TestStepOffset(void)
{
struct timex txc;
/* Zero maxerror and check it's reset to a maximum after ADJ_SETOFFSET.
This seems to be the only way how to verify that the kernel really
supports the ADJ_SETOFFSET mode as it doesn't return an error on unknown
mode. */
txc.modes = ADJ_MAXERROR;
txc.maxerror = 0;
if (adjtimex(&txc) < 0 || txc.maxerror != 0)
return -1;
txc.modes = ADJ_SETOFFSET;
txc.time.tv_sec = 0;
txc.time.tv_usec = 0;
if (adjtimex(&txc) < 0 || txc.maxerror < 100000)
return -1;
return 0;
}
int
TMX_ApplyStepOffset(double offset)
{
struct timex txc;
txc.modes = ADJ_SETOFFSET;
if (offset >= 0) {
txc.time.tv_sec = offset;
} else {
txc.time.tv_sec = offset - 1;
}
/* ADJ_NANO changes the status even with ADJ_SETOFFSET, use it only when
STA_NANO is already enabled */
if (status & STA_PLL) {
txc.modes |= ADJ_NANO;
txc.time.tv_usec = 1e9 * (offset - txc.time.tv_sec);
} else {
txc.time.tv_usec = 1e6 * (offset - txc.time.tv_sec);
}
return adjtimex(&txc);
}

View File

@@ -67,15 +67,16 @@ struct tmx_params {
int TMX_SetTick(long tick);
int TMX_ApplyOffset(long *offset);
int TMX_SetFrequency(double *freq, long tick);
int TMX_GetFrequency(double *freq);
int TMX_GetOffsetLeftOld(long *offset);
int TMX_GetFrequency(double *freq, long *tick);
int TMX_GetOffsetLeft(long *offset);
int TMX_ReadCurrentParams(struct tmx_params *params);
int TMX_SetLeap(int leap);
int TMX_SetSync(int sync);
int TMX_EnableNanoPLL(void);
int TMX_ApplyPLLOffset(long offset);
int TMX_ApplyPLLOffset(long offset, long constant);
int TMX_GetPLLOffsetLeft(long *offset);
int TMX_TestStepOffset(void);
int TMX_ApplyStepOffset(double offset);
#endif /* GOT_WRAP_ADJTIMEX_H */