Compare commits

...

211 Commits
1.31.2 ... 2.1

Author SHA1 Message Date
Miroslav Lichvar
1f0e6296c6 doc: update NEWS 2015-06-22 12:54:52 +02:00
Miroslav Lichvar
ab1f01bacd ntp: use specific reference ID when smoothing served time
Set refid in server/broadcast packets to 127.127.1.255 when a time
smoothing offset is applied to the timestamps. This allows the clients
and administrators to detect that the server is not serving its best
estimate of the true time.
2015-06-22 12:54:50 +02:00
Miroslav Lichvar
b9b896d8e7 ntp: remove unnecessary casting 2015-06-22 12:54:33 +02:00
Miroslav Lichvar
6be54f366c reference: move definition of special refids to ntp.h 2015-06-22 12:54:22 +02:00
Miroslav Lichvar
802cdb3230 test: require latest clknetsim 2015-06-19 14:20:58 +02:00
Miroslav Lichvar
7e27880cb6 doc: update leapsecmode and smoothtime descriptions 2015-06-19 14:20:58 +02:00
Miroslav Lichvar
d3ad85aa43 doc: add Mac OS X to supported platforms 2015-06-18 16:35:26 +02:00
Miroslav Lichvar
59192fc695 update copyright years 2015-06-18 15:30:22 +02:00
Miroslav Lichvar
9095b80c5b doc: refer to authhash command in password command description 2015-06-17 18:31:16 +02:00
Miroslav Lichvar
ed5b78bf09 doc: convert FAQ to AsciiDoc and update it
It's now in a separate file again.
2015-06-17 18:05:14 +02:00
Bryan Christianson
d6aafa3f64 sys: MacOS X driver ported from NetBSD 2015-06-15 14:40:54 +02:00
Miroslav Lichvar
8de04a808d ntp: add debug message to print number of resolved addresses 2015-06-15 13:03:11 +02:00
Miroslav Lichvar
2a299233b3 update NEWS 2015-06-10 14:44:54 +02:00
Miroslav Lichvar
64f83c8861 cmdmon: reply with STT_INVALID on invalid option in handle_manual() 2015-06-09 17:05:45 +02:00
Miroslav Lichvar
1009fe3d9c makefile: warn when Makefile needs to be regenerated 2015-06-09 16:43:56 +02:00
Miroslav Lichvar
ba341fe81a sources: remove unused code in SRC_SelectSource() 2015-06-09 16:15:30 +02:00
Miroslav Lichvar
36e8cb6530 client: add smoothtime command 2015-06-09 16:15:30 +02:00
Miroslav Lichvar
273da62aec cmdmon: add smoothtime command
This adds a command to reset or activate the time smoothing process.
2015-06-09 16:15:30 +02:00
Miroslav Lichvar
41788184a7 client: add smoothing command 2015-06-09 16:15:30 +02:00
Miroslav Lichvar
fb9c2c7dc8 cmdmon: add smoothing command
This adds a new request to get a current report on time smoothing.
2015-06-09 16:15:30 +02:00
Miroslav Lichvar
43116be122 smooth: fix resetting 2015-06-08 17:22:01 +02:00
Miroslav Lichvar
ee038d5de5 cmdmon: use SCH_GetLastEventTime() to get current time
It's cheaper and accurate enough.
2015-06-08 15:07:18 +02:00
Miroslav Lichvar
ea7fae5277 sched: detect timeout overflow in SCH_AddTimeoutByDelay()
Abort when the system time gets so close to the end of 32-bit time_t
that timeouts added by delay start to overflow. This is an addition to
the loop detector in dispatch_timeouts().
2015-06-08 14:49:52 +02:00
Miroslav Lichvar
70b108ab69 array: allow arrays larger than 4 GB
It's not expected we will work with such large arrays anytime soon, but
better be safe than sorry.

Also, limit the number of elements to 2^31-1 to prevent infinite loop in
the calculation of allocated elements.
2015-06-08 14:43:16 +02:00
Miroslav Lichvar
08b152d6a2 test: add 202-prefer 2015-06-08 12:33:46 +02:00
Miroslav Lichvar
83c6213c67 test: add option to override generated server directives on client 2015-06-08 12:33:34 +02:00
Miroslav Lichvar
4253075a97 sources: fix marking of non-preferred selectable sources
When reducing the list of selectable sources to sources with the prefer
option, sources before the first preferred source were left with the
SRC_OK status, which triggered an assertion failure in the next
selection.
2015-06-08 11:54:43 +02:00
Miroslav Lichvar
0abdc2a350 smooth: add option to smooth out only leap seconds
The leaponly option can be used to enable a mode where only leap seconds
are smoothed out and normal offset/frequency changes are ignored. This
is useful to make the interval in which a leap second is smoothed out
constant and allow an NTP client to use multiple leap smearing servers
safely.
2015-06-02 15:24:01 +02:00
Miroslav Lichvar
31669f343a cmdmon: replace definitions of empty requests with null request 2015-06-01 15:00:14 +02:00
Miroslav Lichvar
438b881ab4 cmdmon: set only non-success status in command handling functions 2015-05-28 15:21:25 +02:00
Miroslav Lichvar
27863146a3 cmdmon: refactor allow/deny functions 2015-05-28 14:32:45 +02:00
Miroslav Lichvar
cd4b73612b ntp: include message precision in peer dispersion 2015-05-28 13:49:43 +02:00
Miroslav Lichvar
3c217a9e37 util: add UTI_Log2ToDouble() 2015-05-28 12:51:54 +02:00
Miroslav Lichvar
cde3a003ea util: handle NaN in UTI_FloatHostToNetwork() 2015-05-18 15:51:32 +02:00
Miroslav Lichvar
2c35f56612 client: handle empty hostname before slash in allow/deny commands 2015-05-18 15:36:52 +02:00
Miroslav Lichvar
4295db25d7 doc: remove chrony(1) man page
It's a copy of README, chrony(1) is not a program itself.
2015-05-18 13:15:43 +02:00
Miroslav Lichvar
3c06e57f24 ntp: increase minimum replacement interval to 30 minutes 2015-05-18 13:15:43 +02:00
Miroslav Lichvar
e949cf5967 ntp: replace non-pool sources when unreachable or falsetickers
Sources that are not specified as a pool and have a name (i.e. not
specified by an IP address or added from chronyc) will be replaced with
a newly resolved address of the name when they become unreachable or
falseticker too.
2015-05-18 13:15:42 +02:00
Miroslav Lichvar
4eeaf34295 ntp: add sources specified by IP directly without name resolving 2015-05-18 13:12:00 +02:00
Miroslav Lichvar
2212a90698 ntp: improve alignment of columns in banner for measurements log 2015-05-04 10:23:17 +02:00
Miroslav Lichvar
dc52b61dad doc: update NEWS 2015-04-27 12:58:19 +02:00
Miroslav Lichvar
bbf4c3186b doc: update chrony description 2015-04-27 12:58:19 +02:00
Miroslav Lichvar
f72016a78e doc: document when smoothtime function is activated 2015-04-27 12:27:55 +02:00
Miroslav Lichvar
29b587a9c5 sys: fix TMX_ResetOffset() to set status back correctly 2015-04-27 12:27:55 +02:00
Miroslav Lichvar
cec4f2b140 reference: use 2012 leap second in leapsectz test 2015-04-24 12:16:47 +02:00
Miroslav Lichvar
05278c3b4c sources: ignore reselect distance when combining with refclock 2015-04-20 12:59:12 +02:00
Miroslav Lichvar
1769b8ea0f use return to exit from main function 2015-04-17 17:34:02 +02:00
Miroslav Lichvar
5686bd87d7 client: improve usage line 2015-04-17 17:33:38 +02:00
Miroslav Lichvar
1cda2db45d main: print usage with -h option 2015-04-17 17:30:38 +02:00
Miroslav Lichvar
fdf9640349 ntp: don't log error when socket() fails for client only socket 2015-04-14 15:59:55 +02:00
Miroslav Lichvar
8f2d5d99f1 doc: don't mention ancient systems
Also, don't try to track working versions of supported systems, assume
current versions are ok.
2015-04-13 17:18:19 +02:00
Miroslav Lichvar
61272e7ce8 update copyright years 2015-04-10 11:06:32 +02:00
Miroslav Lichvar
88b76f49cc doc: warn that unauthenticated peers are vulnerable to DoS attack 2015-04-10 10:52:30 +02:00
Miroslav Lichvar
ad942e352d sys: clamp frequency set in generic driver on exit 2015-04-10 10:22:28 +02:00
Miroslav Lichvar
39c2bcd462 util: don't allow time too close to 32-bit time_t overflow
In UTI_IsTimeOffsetSane() consider time in one year interval before
32-bit time_t overflow (in 2038) as invalid. Hopefully everything will
be using 64-bit time_t when that time comes.
2015-04-10 10:05:15 +02:00
Miroslav Lichvar
ae10664b24 doc: fix CVE-ID in NEWS
CVE-2015-1853 is for chrony, CVE-2015-1799 is for ntp.
2015-04-08 08:44:42 +02:00
Miroslav Lichvar
074dac4195 doc: update NEWS 2015-04-07 16:14:09 +02:00
Miroslav Lichvar
a8239b865a Merge branch '1.31-security'
Conflicts:
	NEWS
	ntp_core.c
2015-04-07 15:34:39 +02:00
Miroslav Lichvar
f6a9c5c1b7 sys: allow drivers to fail when applying step offset
Different systems may consider different time values to be valid.
Don't exit on settimeofday()/adjtimex() error in case the check in
UTI_IsTimeOffsetSane() isn't restrictive enough.
2015-04-07 15:23:47 +02:00
Miroslav Lichvar
42774ee851 refclock: check offset sanity 2015-04-07 15:23:47 +02:00
Miroslav Lichvar
4e26f48781 manual: check offset sanity 2015-04-07 15:23:47 +02:00
Miroslav Lichvar
aec97397e8 local: check offset sanity before accumulation
Don't accept an offset that points to time before 1970 or outside the
interval to which is mapped NTP time.
2015-04-07 15:23:47 +02:00
Miroslav Lichvar
183a648d01 local: clamp frequency offset
Don't allow frequency offset larger than 50%, the tracked time must not
stop or run backwards.
2015-04-07 14:13:41 +02:00
Miroslav Lichvar
27f8ad7fd1 cmdmon: fix handling of client access command
Rework the loop to limit the number of iterations to MAX_CLIENT_ACCESSES
and not waste CPU.
2015-04-07 14:07:40 +02:00
Miroslav Lichvar
a79fbef21e ntp: set maximum allowed polling interval
To have an upper bound don't allow polling interval be larger than 24
(194 days).
2015-04-07 14:06:53 +02:00
Miroslav Lichvar
565976acbe doc: document smoothtime directive 2015-04-07 12:38:37 +02:00
Miroslav Lichvar
54bbd2b1c0 doc: update NEWS 2015-04-07 11:09:08 +02:00
Miroslav Lichvar
10b2b53aa7 cmdmon: fix initialization of allocated reply slots
When allocating memory to save unacknowledged replies to authenticated
command requests, the last "next" pointer was not initialized to NULL.
When all allocated reply slots were used, the next reply could be
written to an invalid memory instead of allocating a new slot for it.

An attacker that has the command key and is allowed to access cmdmon
(only localhost is allowed by default) could exploit this to crash
chronyd or possibly execute arbitrary code with the privileges of the
chronyd process.
2015-04-07 11:09:02 +02:00
Miroslav Lichvar
e18ee0bb46 addrfilt: fix access configuration with subnet size indivisible by 4
When NTP or cmdmon access was configured (from chrony.conf or via
authenticated cmdmon) with a subnet size that is indivisible by 4 and
an address that has nonzero bits in the 4-bit subnet remainder (e.g.
192.168.15.0/22 or f000::/3), the new setting was written to an
incorrect location, possibly outside the allocated array.

An attacker that has the command key and is allowed to access cmdmon
(only localhost is allowed by default) could exploit this to crash
chronyd or possibly execute arbitrary code with the privileges of the
chronyd process.
2015-04-07 11:08:30 +02:00
Miroslav Lichvar
857d51ea8e test: extend 113-leapsecond for leap smear 2015-04-07 10:51:07 +02:00
Miroslav Lichvar
ba85544611 ntp: smear leap second with slewing mode and smoothing
Suppress leap second in packets sent to clients when smoothing and leap
second slew mode are enabled.
2015-04-07 10:45:32 +02:00
Miroslav Lichvar
293806d52d test: add 119-smoothtime 2015-04-07 10:42:32 +02:00
Miroslav Lichvar
7f45eb7957 ntp: add server time smoothing
Time smoothing determines an offset that needs to be applied to the
cooked time to make it smooth for external observers. Observed offset
and frequency change slowly and there are no discontinuities. This can
be used on an NTP server to make it easier for the clients to track the
time and keep their clocks close together even when large offset or
frequency corrections are applied to the server's clock (e.g. after
being offline for longer time).

Accumulated offset and frequency are smoothed out in three stages. In
the first stage, the frequency is changed at a constant rate (wander) up
to a maximum, in the second stage the frequency stays at the maximum for
as long as needed and in the third stage the frequency is brought back
to zero.

Time smoothing is configured by the smoothtime directive. It takes two
arguments, maximum frequency offset and maximum wander. It's disabled by
default.
2015-04-07 10:42:26 +02:00
Miroslav Lichvar
f0c48680fe ntp: protect authenticated symmetric associations against DoS attacks
An attacker knowing that NTP hosts A and B are peering with each other
(symmetric association) can send a packet with random timestamps to host
A with source address of B which will set the NTP state variables on A
to the values sent by the attacker. Host A will then send on its next
poll to B a packet with originate timestamp that doesn't match the
transmit timestamp of B and the packet will be dropped. If the attacker
does this periodically for both hosts, they won't be able to synchronize
to each other. It is a denial-of-service attack.

According to [1], NTP authentication is supposed to protect symmetric
associations against this attack, but in the NTPv3 (RFC 1305) and NTPv4
(RFC 5905) specifications the state variables are updated before the
authentication check is performed, which means the association is
vulnerable to the attack even when authentication is enabled.

To fix this problem in chrony, save the originate and local timestamps
only when the authentication check (test5) passed.

[1] https://www.eecis.udel.edu/~mills/onwire.html
2015-04-03 10:48:56 +02:00
Miroslav Lichvar
78283dd822 test: fix source selection check
The chronyd log message changed from "no reachable sources" to "no
selectable sources" in 8f062454.
2015-04-02 16:43:25 +02:00
Miroslav Lichvar
bbdf708d1a reference: update our reference time on slew 2015-03-31 11:51:03 +02:00
Miroslav Lichvar
08195d7e41 sourcestats: fix updating of slope on slew with large residual freq 2015-03-27 10:37:55 +01:00
Miroslav Lichvar
9ff0dbb7a4 test: make 009-sourceselection more reliable 2015-03-27 10:37:55 +01:00
Miroslav Lichvar
6ba97f9161 test: add 118-maxdelay 2015-03-27 10:37:55 +01:00
Miroslav Lichvar
4eca60e7dc test: add 117-fallbackdrift 2015-03-27 10:37:55 +01:00
Miroslav Lichvar
2af6f8cf78 reference: schedule fallback drift even when synchronized
After update to NTPv4 the synchronized status doesn't change when
sources are unreachable, start fallbackdrift timeout on reference update
too.
2015-03-27 10:37:54 +01:00
Miroslav Lichvar
d9a84d24cf reference: don't limit fallback drift offset 2015-03-27 10:37:54 +01:00
Miroslav Lichvar
09ce631e21 reference: fix initial fallback drift setting 2015-03-27 10:37:54 +01:00
Miroslav Lichvar
f93f2a15af ntp: check also reference timestamp in test3
Zero reference timestamp doesn't pass test7, but only before we reach
the next NTP era.
2015-03-27 10:37:54 +01:00
Miroslav Lichvar
47839b7701 cmdmon: remove obsolete request/reply in candm.h 2015-03-27 10:37:54 +01:00
Miroslav Lichvar
41e99afe54 cmdmon: fix noselect flag setting in source data 2015-03-27 10:37:54 +01:00
Miroslav Lichvar
80af04040a ntp: change default maxdelay to 3 seconds 2015-03-27 10:37:54 +01:00
Miroslav Lichvar
3caa1e2f71 doc: document leapsecmode directive 2015-03-27 10:37:54 +01:00
Miroslav Lichvar
ddbbe30b9e test: extend 113-leapsecond to test new leap modes 2015-03-27 10:37:54 +01:00
Miroslav Lichvar
802a98e7fc reference: use step leap mode by default if system is not supported 2015-03-27 10:37:54 +01:00
Miroslav Lichvar
bb21841659 reference: update leap status right after leap second
Don't wait for the next update, there may not be any before the end of
the day.
2015-03-27 10:37:54 +01:00
Miroslav Lichvar
3f9691baff reference: don't report synchronized status during leap second
During inserted leap second the time is invalid, reply with
unsynchronized status to avoid confusing clients that are not smart
enough to ignore measurements close to leap second.
2015-03-27 10:37:54 +01:00
Miroslav Lichvar
f8db832491 reference: add new leap second handling modes
In addition to the system driver handling add new modes to slew or step
the system clock for leap second, or ignore it completely. This can be
configured with leapsecmode directive.
2015-03-27 10:37:48 +01:00
Miroslav Lichvar
c68a92ba80 sys: avoid syslog message when leap bits are not changed
After leap second the kernel removes STA_INS and STA_DEL bits from the
adjtimex status automatically, don't report a change when clearing the
bits.
2015-03-25 15:32:05 +01:00
Miroslav Lichvar
e5cf4645fe refclock: start refid numbering at zero
Commit d92583ed inadvertently changed the refclock refid numbering to
start from 1 instead of 0. Restore the original numbering.
2015-02-17 10:33:03 +01:00
Miroslav Lichvar
fad97e12da ntp: fix maxdelayratio test
This was broken in commit 8fbfe55e.
2015-01-29 12:49:02 +01:00
Miroslav Lichvar
2f6152a580 test: require latest clknetsim 2015-01-28 09:09:08 +01:00
Miroslav Lichvar
7446da8c9b doc: update NEWS 2015-01-27 15:03:57 +01:00
Miroslav Lichvar
00eecd3a1d examples: add chrony.conf.example1
This is a minimal example.
2015-01-27 15:03:57 +01:00
Miroslav Lichvar
46a178cf48 examples: update configuration examples 2015-01-27 15:03:57 +01:00
Miroslav Lichvar
ddcc28f726 examples: rename chrony.conf.example to chrony.conf.example3
Order the examples by complexity.
2015-01-27 15:03:57 +01:00
Miroslav Lichvar
04f86aa2ff doc: update chrony.conf man page 2015-01-27 15:03:57 +01:00
Miroslav Lichvar
72f0f99ac3 doc: update chrony.texi 2015-01-27 14:52:32 +01:00
Miroslav Lichvar
c8fe0fe992 test: add compilation test
Check if chrony can be compiled in various combination of disabled
features. This should fail if there are missing functions in stubs.c.
2015-01-26 12:16:17 +01:00
Miroslav Lichvar
be5c3b0b90 clientlog: remove unused code 2015-01-26 11:38:02 +01:00
Miroslav Lichvar
5194101c8b cmdmon: bind to loopback interface by default 2015-01-26 10:40:15 +01:00
Miroslav Lichvar
0ee27c6ef6 cmdmon: use system values for loopback addresses 2015-01-26 10:40:15 +01:00
Miroslav Lichvar
46a0aab6b9 test: require latest clknetsim 2015-01-26 10:40:15 +01:00
Miroslav Lichvar
55fb7abc39 contrib: remove DNSchrony from distribution
With the new pool directive chronyd is now able to replace unreachable
NTP servers with newly resolved addresses automatically. Starting
without DNS wasn't a problem since 1.25.
2015-01-26 10:39:58 +01:00
Miroslav Lichvar
407e47b306 ntp: remove unnecessary check in read_from_socket() 2015-01-22 15:38:41 +01:00
Miroslav Lichvar
4e54770f18 create NTP and cmdmon sockets after root drop
This is now possible as we keep the cap_net_bind_service capability.
2015-01-22 15:38:39 +01:00
Miroslav Lichvar
f9a31f36a0 ntp: keep all length constants signed
This should make it harder to accidentally create an unsafe comparison
between signed and unsigned values.
2015-01-22 14:37:35 +01:00
Miroslav Lichvar
547272e66c ntp: use different value for invalid socket in ntp_core
This should make it easier to see invalid sockets leaking from ntp_core
to ntp_io.
2015-01-07 16:14:29 +01:00
Miroslav Lichvar
35e11ffe60 ntp: fix length check of NTPv4 extension fields
Don't allow extension fields shorter than 16 bytes.
2015-01-07 14:12:29 +01:00
Miroslav Lichvar
52e12e42e5 ntp: open server socket only when access is allowed
When changing access configuration, check if any address is allowed and
open/close the server socket as needed.
2015-01-06 16:35:12 +01:00
Miroslav Lichvar
5214d42c07 ntp: count references to NTP server sockets
Server sockets are now explicitly opened and closed for normal NTP
server, NTP broadcast and NTP peering. This will allow closing the
NTP port when not needed.
2015-01-06 16:33:49 +01:00
Miroslav Lichvar
40bbe2539b sys: keep cap_net_bind_service capability
This will be needed to allow opening of NTP server socket after root
privileges are dropped.
2015-01-06 15:28:22 +01:00
Miroslav Lichvar
6d1dda0fad ntp: rename NIO_Get*Socket functions 2015-01-05 14:17:21 +01:00
Miroslav Lichvar
7a90dab8ff doc: improve FAQ section on improving accuracy 2014-12-17 19:58:23 +01:00
Miroslav Lichvar
395c89cff2 doc: use example.net domain in examples 2014-12-17 16:51:48 +01:00
Miroslav Lichvar
aad242d54b doc: update description of tracking command
Negative root delay is never reported with the current code.
2014-12-17 16:21:19 +01:00
Miroslav Lichvar
220ef264fb doc: list server/peer options that can be set in chronyc 2014-12-15 18:21:56 +01:00
Miroslav Lichvar
f64dcc0ac2 doc: fix examples of add server and add peer commands 2014-12-15 18:21:56 +01:00
Miroslav Lichvar
e57abae138 cmdparse: add function to convert error status to string
This is used to avoid duplication of error printing in chronyd and
chronyc.
2014-12-15 18:21:51 +01:00
Miroslav Lichvar
fc73accfe5 sys: use system headers for adjtimex 2014-12-15 17:25:37 +01:00
Miroslav Lichvar
c4d57f0e3d sys: remove shift_hz
It's not used for anything since commit e147f2f1.
2014-12-10 15:58:27 +01:00
Miroslav Lichvar
eadabfe890 sys: remove TMX_ReadCurrentParams 2014-12-10 15:58:27 +01:00
Miroslav Lichvar
02cbe5e1ad sys: add sync status setting to generic and Linux driver
Set the adjtimex status, esterror and maxerror fields to the values
provided by the reference module.
2014-12-10 15:58:13 +01:00
Miroslav Lichvar
2645e632a8 sys: fix formatting in sys_linux.c 2014-12-10 15:35:56 +01:00
Miroslav Lichvar
e14a03a172 local: add new driver call to set synchronization status
This will be used to set the kernel adjtimex() variables to allow other
applications running on the system to know if the system clock is
synchronized and the estimated error and the maximum error.
2014-12-10 15:35:56 +01:00
Miroslav Lichvar
513e65900c client: add second form of makestep command
The second form configures the automatic stepping, similarly to the
makestep directive. It has two parameters, stepping threshold (in
seconds) and number of future clock updates for which will be the
threshold active. This can be used with the burst command to quickly
make a new measurement and correct the clock by stepping if needed,
without waiting for chronyd to complete the measurement and update the
clock.
2014-12-09 12:31:56 +01:00
Miroslav Lichvar
4b81cda521 cmdmon: initialize new source params when adding source 2014-12-09 11:40:19 +01:00
Miroslav Lichvar
6688f40325 sources: allow setting minsamples and maxsamples for each source
The minsamples and maxsamples directives now set the default value,
which can be overriden for individual sources in the server/peer/pool
and refclock directives.
2014-12-03 16:27:51 +01:00
Miroslav Lichvar
42dd5caa1b ntp: don't replace source instance when changing address
Add new functions to change source's reference ID/address and reset the
instance. Use that instead of destroying and creating a new instance
when the NTP address is changed.
2014-12-01 18:40:47 +01:00
Miroslav Lichvar
308bcae257 ntp: limit number of pool sources
A new option can be now used in the pool directive: maxsources sets the
maximum number of sources that can be used from the pool, the default
value is 4.

On start, when the pool name is resolved, chronyd will add up to 16
sources, one for each resolved address. When the number of sources from
which at least one valid reply was received reaches maxsources, the
other sources will be removed.
2014-11-26 17:56:36 +01:00
Miroslav Lichvar
f2c80cae44 ntp: update number of sources when removing all sources
Also, rehash the records after removal and split cleaning of the source
record to a separate function.
2014-11-26 17:56:29 +01:00
Miroslav Lichvar
aaf744dfab ntp: return status from NCR_ProcessKnown() 2014-11-24 16:14:04 +01:00
Miroslav Lichvar
7534ffee64 doc: update tempcomp description 2014-11-21 13:13:15 +01:00
Miroslav Lichvar
ed862c8d08 tempcomp: allow configuration with list of points
In addition to the quadratic function, allow configuration of the
compensation with a file containing list of (temperature, compensation)
points used for linear interpolation and extrapolation.
2014-11-21 13:11:16 +01:00
Miroslav Lichvar
1d977e021d test: fix 111-knownclient
The new NTPv4 loop synchronization check fails as clknetsim doesn't
support IP_PKTINFO yet. Use the noselect option to prevent the server to
synchronize to the client.
2014-11-21 11:44:15 +01:00
Miroslav Lichvar
dccd61966a ntp: fix accepting requests from configured sources
When using server socket to send client requests (acquisitionport 123)
and currently not waiting for a reply, the socket check will fail for
client requests from the source.

The check needs to be moved to correctly handle the requests as from an
unknown source.
2014-11-21 11:43:47 +01:00
Miroslav Lichvar
93aeecefeb tempcomp: fix double free on sensor filename
This is related to commit f6ed7844e1.
2014-11-04 11:28:29 +01:00
Miroslav Lichvar
df63790bb3 conf: change default stratumweight to 0.001 2014-11-03 15:13:52 +01:00
Miroslav Lichvar
c743ecbf50 ntp: support pools
The pool directive can be used to configure chronyd for a pool of NTP
servers (e.g. pool.ntp.org). The name is expected to resolve to multiple
addresses which change over time.

On start, a source will be added for each resolved address. When a
source from the pool is unreachable or marked as falseticker, chronyd
will try to replace the source with a newly resolved address of the
pool.

The minimum interval between replacements is currently set to 244
seconds to avoid frequent DNS requests.
2014-11-03 11:18:04 +01:00
Miroslav Lichvar
29c1df4610 ntp: allow changing address of core instance 2014-11-03 11:15:20 +01:00
Miroslav Lichvar
40f8591257 ntp: try adding other server addresses
When adding a server from configuration file, don't give up when the
first returned address was already added for another server directive,
but try adding other addresses until one succeeds.
2014-10-31 17:01:03 +01:00
Miroslav Lichvar
4d1a754ec6 nameserv: add support for returning multiple addresses 2014-10-23 16:48:13 +02:00
Miroslav Lichvar
699680807d nameserv: check that address returned from gethostbyname() is IPv4
Also, always return failure with -6.
2014-10-23 15:06:00 +02:00
Miroslav Lichvar
ccaf0874e1 ntp: take auto_offline sources offline before sending new request 2014-10-23 15:06:00 +02:00
Miroslav Lichvar
1afcb4f29a test: add 116-minsources 2014-10-20 18:05:20 +02:00
Miroslav Lichvar
1bb2732056 sources: add minsources option
This sets the minimum number of selectable sources needed to update the
local clock.
2014-10-20 18:04:37 +02:00
Miroslav Lichvar
6744ad392d docs: fix formatting of examples in server options 2014-10-20 16:17:38 +02:00
Miroslav Lichvar
1aecc51c70 ntp: add version option to server/peer directive 2014-10-20 16:14:17 +02:00
Miroslav Lichvar
c9571e55f5 conf: use array for broadcast destinations 2014-10-20 13:05:55 +02:00
Miroslav Lichvar
aba4596ba9 conf: use arrays for NTP and cmdmon restrictions 2014-10-20 12:54:16 +02:00
Miroslav Lichvar
bd3cfeae92 test: add 009-sourceselection 2014-10-20 12:26:49 +02:00
Miroslav Lichvar
9ef723eb97 test: add option to create falsetickers 2014-10-20 12:26:29 +02:00
Miroslav Lichvar
7958b1764e ntp: remove debug messages in slew handler 2014-10-20 12:22:17 +02:00
Miroslav Lichvar
44f612acbc sourcestats: reduce debug messages in slew handler 2014-10-20 12:22:16 +02:00
Miroslav Lichvar
5d7df69116 sources: reset reachability for offline sources
With the recent change allowing unreachable sources to remain selected,
offline sources will now be selectable only for some time, similarly to
online unreachable sources.
2014-10-20 12:19:36 +02:00
Miroslav Lichvar
8f06245428 sources: allow selection of unreachable sources
Reachability is no longer a requirement for selection. An unreachable
source can remain selected if its newest sample is not older than the
oldest sample from all reachable sources.

This is useful to prevent reselection when an accurate source uses a
very short polling interval (e.g. refclock) and is occasionally
unreachable for short periods of time.
2014-10-20 12:19:36 +02:00
Miroslav Lichvar
0f8368bcf1 sources: extend source status tracking
Add new source states and rename some states so there is one state for
each reason a source can be rejected in the source selection.

This fixes reported status when sources are selectable, but the actual
selection was postponed until next update. It will also allow more
detailed reports when the cmdmon protocol is updated.
2014-10-20 11:23:48 +02:00
Miroslav Lichvar
5d0356a75e sources: fix reported normal select option 2014-10-20 11:19:45 +02:00
Miroslav Lichvar
5f68941241 sources: select only when reference can be updated
Before selecting the new synchronization source wait until the reference
can be updated, i.e. the source has new samples.
2014-10-20 11:19:28 +02:00
Miroslav Lichvar
63af4889f6 sources: drop selectable flag
This is no longer needed with new NTP packet processing as the sources
are always selectable after first sample is accumulated.
2014-10-20 11:02:07 +02:00
Miroslav Lichvar
6f84d2fac1 sources: reorder SRC_SelectSource()
Reorder the code to improve readability and also update coding style.
No functional changes.
2014-10-20 11:02:07 +02:00
Miroslav Lichvar
049eae661a sources: keep synchronized status with unreachable/unselectable sources
Following RFC 5905, don't call REF_SetUnsynchronised() when there are no
reachable or selectable sources. It's up to the client to consider the
source unsynchronized when the root distance exceeds a threshold.

The unsynchronized status is still set when no majority is reached.
2014-10-20 11:02:07 +02:00
Miroslav Lichvar
e930d94728 sources: update reference only with new sample
This follows the section 11.2.3. from RFC 5905.
2014-10-20 11:02:07 +02:00
Miroslav Lichvar
819b8eb73d ntp: fix Clang warning 2014-10-15 12:40:12 +02:00
Miroslav Lichvar
a78bf0c34e ntp: merge broadcast code with ntp_core 2014-10-15 12:27:46 +02:00
Miroslav Lichvar
e0059bcc6b ntp: define NTP_MAX_STRATUM for other modules 2014-10-14 17:25:55 +02:00
Miroslav Lichvar
af0b83a2c3 doc: update for NTPv4 support 2014-10-14 16:57:01 +02:00
Miroslav Lichvar
2c033989b6 Update comments referencing RFC 1305 2014-10-14 16:52:22 +02:00
Miroslav Lichvar
8fbfe55e92 ntp: update packet processing to NTPv4 (RFC 5905) 2014-10-14 16:52:22 +02:00
Miroslav Lichvar
740e8130dd ntp: clamp value set by minstratum option 2014-10-13 15:10:15 +02:00
Miroslav Lichvar
5bddaf6820 sources: use correct specifier for refid in debug message 2014-10-13 15:10:15 +02:00
Miroslav Lichvar
c36230e21b ntp: print number of bytes sent in debug message 2014-10-13 15:10:15 +02:00
Miroslav Lichvar
15d8c08eaa ntp: enable PKTINFO on client sockets
This will be useful to detect synchronization loops.
2014-10-08 15:13:02 +02:00
Miroslav Lichvar
2f738d5805 util: fix sockaddr function naming 2014-10-03 10:15:18 +02:00
Miroslav Lichvar
e05b687009 client: improve sources caption 2014-09-29 11:29:51 +02:00
Miroslav Lichvar
55a22656b8 util: use common functions to convert to/from sockaddr 2014-09-26 17:54:45 +02:00
Miroslav Lichvar
2db20adc3e client: print full date in manual list 2014-09-26 15:47:57 +02:00
Miroslav Lichvar
c7eeb57a32 ntp: fix NSR_TakeSourcesOffline()
This was broken when switching to dynamic allocation in commit 9e7193.
2014-09-26 15:27:08 +02:00
Miroslav Lichvar
361726b3ae keys: store IDs in uint32_t 2014-09-26 14:14:54 +02:00
Miroslav Lichvar
c404786b92 logging: remove warning on missing debug messages
The state of the DEBUG feature is now printed with chronyd version.
2014-09-25 11:12:23 +02:00
Miroslav Lichvar
2ff4eca7bf cmdmon: fix initialization of allocated reply slots
The next pointer in the last allocated reply slot was not set. This
could cause a crash when more slots were needed. (the slots are used to
save unacknowledged replies to authenticated commands)
2014-09-25 10:58:57 +02:00
Miroslav Lichvar
1eca83ff22 cmdmon: allocate reply slots in smaller quantums 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
2575fa8f83 cmdmon: use char for permissions table 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
b7e86192ee refclock: include refid in some debug messages 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
078f0f511e util: optimize UTI_RefidToString() 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
4963b931d0 rtc: allocate samples dynamically 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
75fd327222 conf: allocate sources dynamically
This removes the limits on maximum number of sources specified by the
initstepslew, server and refclock directives in the config file.
2014-09-25 10:58:57 +02:00
Miroslav Lichvar
9e71932c2e ntp: allocate source records dynamically
This removes the limit on maximum number of added NTP sources.
2014-09-25 10:58:57 +02:00
Miroslav Lichvar
d92583ed33 refclocks: allocate refclock instances dynamically 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
cd27860e55 keys: allocate keys dynamically
This removes the limit on maximum number of keys in the key file.
2014-09-25 10:58:57 +02:00
Miroslav Lichvar
ba875fc04a sched: allocate file handlers dynamically 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
b5a85bd2fe sources: reallocate arrays in exponentially increasing sizes 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
4e0df8c2a6 ntp: improve hashing of sources
Use 32-bit hash and switch to quadratic probing. This will be useful to
allow resizing of the hash table and not limit the number of sources.
2014-09-25 10:58:57 +02:00
Miroslav Lichvar
37bc30c8d9 Add array utility functions 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
f6ed7844e1 Free allocated memory on exit
This should reduce the number of possible memory leaks reported by
valgrind. The remaining reported leaks are sched tqe allocation, async
DNS instance allocation, cmdmon response/timestamp cell allocation, and
clientlog subnet allocation.
2014-09-25 10:57:55 +02:00
Miroslav Lichvar
d466390233 cmdparse: don't duplicate hostname in CPS_ParseNTPSourceAdd()
Let the caller duplicate the string if needed.
2014-09-24 12:43:11 +02:00
Miroslav Lichvar
336473398a Check for memory allocation errors 2014-09-23 15:47:02 +02:00
Miroslav Lichvar
bb16c81e7b test: make 114-presend more tolerant 2014-09-23 15:46:27 +02:00
Miroslav Lichvar
f955b46c13 nameserv: move fallback DNS_Name2IPAddressAsync() to stubs.c 2014-09-22 13:14:16 +02:00
Miroslav Lichvar
b54711252b configure: add --disable-sechash option 2014-09-22 13:14:16 +02:00
Miroslav Lichvar
f2710d5b55 Print enabled/disabled features with version 2014-09-22 13:14:16 +02:00
Miroslav Lichvar
285fae856d configure: unify macro naming for optional features 2014-09-22 13:14:16 +02:00
Miroslav Lichvar
111b63bb16 configure: allow building without cmdmon, NTP, refclock support 2014-09-22 13:14:11 +02:00
Miroslav Lichvar
767a8b19a9 configure: unify macro naming for available headers 2014-09-19 11:06:37 +02:00
Miroslav Lichvar
cb28d6cdb7 configure: don't remove config files with --help 2014-09-19 10:13:42 +02:00
Miroslav Lichvar
a0d5abef88 sourcestats: remove tracking of skew change
This is not used since commit 7a6ee1d.
2014-09-19 10:07:03 +02:00
110 changed files with 6454 additions and 4893 deletions

2
.gitignore vendored
View File

@@ -2,6 +2,8 @@
.vimrc
*.o
*.swp
*.dSYM
*.DS_Store
RELEASES
Makefile
chrony.conf.5

View File

@@ -38,14 +38,9 @@ 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 keys.o \
nameserv.o nameserv_async.o manual.o addrfilt.o \
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
broadcast.o refclock.o refclock_phc.o refclock_pps.o \
refclock_shm.o refclock_sock.o tempcomp.o $(HASH_OBJ)
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o mkdirpp.o \
reference.o regress.o rtc.o sched.o sources.o sourcestats.o stubs.o \
sys.o smooth.o tempcomp.o util.o $(HASH_OBJ)
EXTRA_OBJS=@EXTRA_OBJECTS@
@@ -78,12 +73,14 @@ $(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
distclean : clean
-rm -f .DS_Store
-rm -f Makefile
-rm -f chrony.conf.5 chrony.texi chronyc.1 chronyd.8
clean :
-rm -f *.o *.s chronyc chronyd core *~ chrony.info chrony.html chrony.txt
-rm -rf .deps
-rm -rf *.dSYM
getdate.c :
bison -o getdate.c getdate.y
@@ -117,8 +114,6 @@ install: chronyd chronyc chrony.txt
chmod 644 $(DESTDIR)$(DOCDIR)/COPYING
cp README $(DESTDIR)$(DOCDIR)/README
chmod 644 $(DESTDIR)$(DOCDIR)/README
cp chrony.1 $(DESTDIR)$(MANDIR)/man1
chmod 644 $(DESTDIR)$(MANDIR)/man1/chrony.1
cp chronyc.1 $(DESTDIR)$(MANDIR)/man1
chmod 644 $(DESTDIR)$(MANDIR)/man1/chronyc.1
cp chronyd.8 $(DESTDIR)$(MANDIR)/man8
@@ -157,6 +152,12 @@ chrony.html : chrony.texi
chrony.info : chrony.texi
makeinfo chrony.texi
Makefile : Makefile.in configure
@echo
@echo Makefile needs to be regenerated, run ./configure
@echo
@exit 1
.deps:
@mkdir .deps

67
NEWS
View File

@@ -1,3 +1,70 @@
New in version 2.1
==================
Enhancements
------------
* Add support for Mac OS X
* Try to replace unreachable and falseticker servers/peers specified
by name like pool sources
* Add leaponly option to smoothtime directive to allow synchronised
leap smear between multiple servers
* Use specific reference ID when smoothing served time
* Add smoothing command to report time smoothing status
* Add smoothtime command to activate or reset time smoothing
Bug fixes
---------
* Fix crash in source selection with preferred sources
* Fix resetting of time smoothing
* Include packet precision in peer dispersion
* Fix crash in chronyc on invalid command syntax
New in version 2.0
==================
Enhancements
------------
* Update to NTP version 4 (RFC 5905)
* Add pool directive to specify pool of NTP servers
* Add leapsecmode directive to select how to correct clock for leap second
* Add smoothtime directive to smooth served time and enable leap smear
* Add minsources directive to set required number of selectable sources
* Add minsamples and maxsamples options for all sources
* Add tempcomp configuration with list of points
* Allow unlimited number of NTP sources, refclocks and keys
* Allow unreachable sources to remain selected
* Improve source selection
* Handle offline sources as unreachable
* Open NTP server port only when necessary (client access is allowed by
allow directive/command or peer/broadcast is configured)
* Change default bindcmdaddress to loopback address
* Change default maxdelay to 3 seconds
* Change default stratumweight to 0.001
* Update adjtimex synchronisation status
* Use system headers for adjtimex
* Check for memory allocation errors
* Reduce memory usage
* Add configure options to compile without NTP, cmdmon, refclock support
* Extend makestep command to set automatic clock stepping
Bug fixes
---------
* Add sanity checks for time and frequency offset
* Don't report synchronised status during leap second
* Don't combine reference clocks with close NTP sources
* Fix accepting requests from configured sources
* Fix initial fallback drift setting
New in version 1.31.1
=====================
Security fixes
--------------
* Protect authenticated symmetric NTP associations against DoS attacks
(CVE-2015-1853)
* Fix access configuration with subnet size indivisible by 4 (CVE-2015-1821)
* Fix initialization of reply slots for authenticated commands (CVE-2015-1822)
New in version 1.31
===================

83
README
View File

@@ -3,66 +3,35 @@ This is the README for chrony.
What is chrony?
===============
Chrony is a pair of programs for maintaining the accuracy of computer
clocks.
chrony is a versatile implementation of the Network Time Protocol (NTP).
It can synchronize the system clock with NTP servers, reference clocks
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
a time service to other computers in the network.
chronyd is a (background) daemon program that can be started at boot
time. This does most of the work.
It is designed to perform well in a wide range of conditions, including
intermittent network connections, heavily congested networks, changing
temperatures (ordinary computer clocks are sensitive to temperature),
and systems that do not run continuosly, or run on a virtual machine.
chronyc is a command-line interface program which can be used to
monitor chronyd's performance and to change various operating
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
accordingly. It also works out the rate at which the system clock
gains or loses time and uses this information to keep it accurate
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.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 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
reboots.
Typical accuracies available between 2 machines are
On an ethernet LAN : 100-200 microseconds, often much better
On a V32bis dial-up modem connection : 10's of milliseconds (from one
session to the next)
With a good reference clock the accuracy can reach one microsecond.
chronyd can also operate as an RFC1305-compatible NTP server and peer.
Typical accuracy between two machines on a LAN is in tens, or a few
hundreds, of microseconds; over the Internet, accuracy is typically
within a few milliseconds. With a good hardware reference clock
sub-microsecond accuracy is possible.
Two programs are included in chrony, chronyd is a daemon that can be
started at boot time and chronyc is a command-line interface program
which can be used to monitor chronyd's performance and to change various
operating parameters whilst it is running.
What will chrony run on?
========================
Chrony can be successfully built and run on
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)
3. SunOS 4.1.4 (Sparc 2 and Sparc 20)
4. BSD/386 v1.1 has been reported to work using the SunOS 4.1 driver.
5. NetBSD.
Any other system will require a porting exercise. You would need to
start from one of the existing system-specific drivers and look into
the quirks of certain system calls and the kernel on your target
system.
The software is known to work on Linux, FreeBSD, NetBSD, Mac OS X and
Solaris. Closely related systems may work too. Any other system will
likely require a porting exercise. You would need to start from one
of the existing system-specific drivers and look into the quirks of
certain system calls and the kernel on your target system.
How do I set it up?
===================
@@ -115,6 +84,11 @@ chrony-dev-request@chrony.tuxfamily.org
as applicable.
License
=======
chrony is distributed under the GNU General Public License version 2.
Author
======
@@ -154,6 +128,9 @@ Stephan I. Boettcher <stephan@nevis1.columbia.edu>
Erik Bryer <ebryer@spots.ab.ca>
Entries in contrib directory
Bryan Christianson <bryan@whatroute.net>
Support for Mac OS X
Juliusz Chroboczek <jch@pps.jussieu.fr>
Fix install rule in Makefile if chronyd file is in use.

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997,1998,1999,2000,2001,2002,2005
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009, 2015
*
* 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
@@ -199,7 +199,10 @@ set_subnet(TableNode *start_node,
/* How many subnet entries to set : 1->8, 2->4, 3->2 */
N = 1 << (NBITS-bits_to_go);
subnet = get_subnet(ip, bits_consumed);
subnet = get_subnet(ip, bits_consumed) & ~(N - 1);
assert(subnet + N <= TABLE_SIZE);
if (!(node->extended)) {
open_node(node);
}
@@ -363,6 +366,44 @@ ADF_IsAllowed(ADF_AuthTable table,
/* ================================================== */
static int
is_any_allowed(TableNode *node, State parent)
{
State state;
int i;
state = node->state != AS_PARENT ? node->state : parent;
assert(state != AS_PARENT);
if (node->extended) {
for (i = 0; i < TABLE_SIZE; i++) {
if (is_any_allowed(&node->extended[i], state))
return 1;
}
} else if (state == ALLOW) {
return 1;
}
return 0;
}
/* ================================================== */
int
ADF_IsAnyAllowed(ADF_AuthTable table, int family)
{
switch (family) {
case IPADDR_INET4:
return is_any_allowed(&table->base4, AS_PARENT);
case IPADDR_INET6:
return is_any_allowed(&table->base6, AS_PARENT);
default:
return 0;
}
}
/* ================================================== */
#if defined TEST
static void print_node(TableNode *node, uint32_t *addr, int ip_len, int shift, int subnet_bits)

View File

@@ -72,4 +72,9 @@ extern void ADF_DestroyTable(ADF_AuthTable table);
extern int ADF_IsAllowed(ADF_AuthTable table,
IPAddr *ip);
/* Check if at least one address from a given family is allowed by
the rules in the table */
extern int ADF_IsAnyAllowed(ADF_AuthTable table,
int family);
#endif /* GOT_ADDRFILT_H */

129
array.c Normal file
View File

@@ -0,0 +1,129 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014
*
* 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.
*
**********************************************************************
=======================================================================
Functions implementing an array with automatic memory allocation.
*/
#include "config.h"
#include "sysincl.h"
#include "array.h"
#include "memory.h"
struct ARR_Instance_Record {
void *data;
unsigned int elem_size;
unsigned int used;
unsigned int allocated;
};
ARR_Instance
ARR_CreateInstance(unsigned int elem_size)
{
ARR_Instance array;
assert(elem_size > 0);
array = MallocNew(struct ARR_Instance_Record);
array->data = NULL;
array->elem_size = elem_size;
array->used = 0;
array->allocated = 0;
return array;
}
void
ARR_DestroyInstance(ARR_Instance array)
{
Free(array->data);
Free(array);
}
static void
realloc_array(ARR_Instance array, unsigned int min_size)
{
size_t data_size;
assert(min_size <= 2 * min_size);
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
return;
if (array->allocated < min_size) {
while (array->allocated < min_size)
array->allocated = array->allocated ? 2 * array->allocated : 1;
} else {
array->allocated = min_size;
}
data_size = (size_t)array->elem_size * array->allocated;
assert(data_size / array->elem_size == array->allocated);
array->data = Realloc(array->data, data_size);
}
void *
ARR_GetNewElement(ARR_Instance array)
{
array->used++;
realloc_array(array, array->used);
return ARR_GetElement(array, array->used - 1);
}
void *
ARR_GetElement(ARR_Instance array, unsigned int index)
{
assert(index < array->used);
return (void *)((char *)array->data + (size_t)index * array->elem_size);
}
void *
ARR_GetElements(ARR_Instance array)
{
return array->data;
}
void
ARR_AppendElement(ARR_Instance array, void *element)
{
void *e;
e = ARR_GetNewElement(array);
memcpy(e, element, array->elem_size);
}
void
ARR_SetSize(ARR_Instance array, unsigned int size)
{
realloc_array(array, size);
array->used = size;
}
unsigned int
ARR_GetSize(ARR_Instance array)
{
return array->used;
}

56
array.h Normal file
View File

@@ -0,0 +1,56 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014
*
* 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 array functions.
*/
#ifndef GOT_ARRAY_H
#define GOT_ARRAY_H
typedef struct ARR_Instance_Record *ARR_Instance;
/* Create a new array with given element size */
extern ARR_Instance ARR_CreateInstance(unsigned int elem_size);
/* Destroy the array */
extern void ARR_DestroyInstance(ARR_Instance array);
/* Return pointer to a new element added to the end of the array */
extern void *ARR_GetNewElement(ARR_Instance array);
/* Return element with given index */
extern void *ARR_GetElement(ARR_Instance array, unsigned int index);
/* Return pointer to the internal array of elements */
extern void *ARR_GetElements(ARR_Instance array);
/* Add a new element to the end of the array */
extern void ARR_AppendElement(ARR_Instance array, void *element);
/* Set the size of the array */
extern void ARR_SetSize(ARR_Instance array, unsigned int size);
/* Return current size of the array */
extern unsigned int ARR_GetSize(ARR_Instance array);
#endif

View File

@@ -1,159 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
*
* 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.
*
**********************************************************************
=======================================================================
Deal with broadcast server functions.
*/
#include "config.h"
#include "sysincl.h"
#include "memory.h"
#include "addressing.h"
#include "broadcast.h"
#include "sched.h"
#include "ntp.h"
#include "local.h"
#include "reference.h"
#include "util.h"
#include "ntp_io.h"
typedef struct {
NTP_Remote_Address addr;
NTP_Local_Address local_addr;
int interval;
} Destination;
static Destination *destinations = 0;
static int n_destinations = 0;
static int max_destinations = 0;
void
BRD_Initialise(void)
{
}
/* ================================================== */
void
BRD_Finalise(void)
{
}
/* ================================================== */
/* This is a cut-down version of what transmit_packet in ntp_core.c does */
static void
timeout_handler(void *arbitrary)
{
Destination *d = (Destination *) arbitrary;
NTP_Packet message;
/* Parameters read from reference module */
int version;
int leap;
int are_we_synchronised, our_stratum;
NTP_Leap leap_status;
uint32_t our_ref_id, ts_fuzz;
struct timeval our_ref_time;
double our_root_delay, our_root_dispersion;
struct timeval local_transmit;
version = 3;
LCL_ReadCookedTime(&local_transmit, NULL);
REF_GetReferenceParams(&local_transmit,
&are_we_synchronised, &leap_status,
&our_stratum,
&our_ref_id, &our_ref_time,
&our_root_delay, &our_root_dispersion);
if (are_we_synchronised) {
leap = (int) leap_status;
} else {
leap = LEAP_Unsynchronised;
}
message.lvm = ((leap << 6) &0xc0) | ((version << 3) & 0x38) | (MODE_BROADCAST & 0x07);
message.stratum = our_stratum;
message.poll = 6; /* FIXME: what should this be? */
message.precision = LCL_GetSysPrecisionAsLog();
/* If we're sending a client mode packet and we aren't synchronized yet,
we might have to set up artificial values for some of these parameters */
message.root_delay = UTI_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, 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, ts_fuzz);
NIO_SendNormalPacket(&message, &d->addr, &d->local_addr);
/* Requeue timeout. Don't care if interval drifts gradually, so just do it
* at the end. */
SCH_AddTimeoutInClass((double) d->interval, 1.0, 0.02,
SCH_NtpBroadcastClass,
timeout_handler, (void *) d);
}
/* ================================================== */
void
BRD_AddDestination(IPAddr *addr, unsigned short port, int interval)
{
if (max_destinations == n_destinations) {
/* Expand array */
max_destinations += 8;
if (destinations) {
destinations = ReallocArray(Destination, max_destinations, destinations);
} else {
destinations = MallocArray(Destination, max_destinations);
}
}
destinations[n_destinations].addr.ip_addr = *addr;
destinations[n_destinations].addr.port = port;
destinations[n_destinations].local_addr.ip_addr.family = IPADDR_UNSPEC;
destinations[n_destinations].local_addr.sock_fd =
NIO_GetServerSocket(&destinations[n_destinations].addr);
destinations[n_destinations].interval = interval;
SCH_AddTimeoutInClass((double) interval, 1.0, 0.0,
SCH_NtpBroadcastClass,
timeout_handler, (void *)(destinations + n_destinations));
++n_destinations;
}

112
candm.h
View File

@@ -88,7 +88,10 @@
#define REQ_MODIFY_MAXDELAYDEVRATIO 47
#define REQ_RESELECT 48
#define REQ_RESELECTDISTANCE 49
#define N_REQUEST_TYPES 50
#define REQ_MODIFY_MAKESTEP 50
#define REQ_SMOOTHING 51
#define REQ_SMOOTHTIME 52
#define N_REQUEST_TYPES 53
/* Special utoken value used to log on with first exchange being the
password. (This time value has long since gone by) */
@@ -115,6 +118,10 @@ typedef struct {
pktlength.c, to get the number of bytes that ought to be
transmitted for each packet type. */
typedef struct {
int32_t EOR;
} REQ_Null;
typedef struct {
IPAddr mask;
IPAddr address;
@@ -187,6 +194,12 @@ typedef struct {
int32_t EOR;
} REQ_Modify_Maxupdateskew;
typedef struct {
int32_t limit;
Float threshold;
int32_t EOR;
} REQ_Modify_Makestep;
typedef struct {
Timeval ts;
int32_t EOR;
@@ -208,19 +221,11 @@ typedef struct {
int32_t EOR;
} REQ_Manual;
typedef struct {
int32_t EOR;
} REQ_N_Sources;
typedef struct {
int32_t index;
int32_t EOR;
} REQ_Source_Data;
typedef struct {
int32_t EOR;
} REQ_Rekey;
typedef struct {
IPAddr ip;
int32_t subnet_bits;
@@ -257,10 +262,6 @@ typedef struct {
int32_t EOR;
} REQ_Del_Source;
typedef struct {
int32_t EOR;
} REQ_WriteRtc;
typedef struct {
Float dfreq;
int32_t EOR;
@@ -272,32 +273,11 @@ typedef struct {
int32_t EOR;
} REQ_Doffset;
typedef struct {
int32_t EOR;
} REQ_Tracking;
typedef struct {
uint32_t index;
int32_t EOR;
} REQ_Sourcestats;
typedef struct {
int32_t EOR;
} REQ_RTCReport;
typedef struct {
int32_t EOR;
} REQ_TrimRTC;
typedef struct {
int32_t EOR;
} REQ_CycleLogs;
typedef struct {
IPAddr ip;
uint32_t bits_specd;
} REQ_SubnetsAccessed_Subnet;
/* This is based on the response size rather than the
request size */
#define MAX_CLIENT_ACCESSES 8
@@ -308,32 +288,24 @@ typedef struct {
int32_t EOR;
} REQ_ClientAccessesByIndex;
typedef struct {
int32_t EOR;
} REQ_ManualList;
typedef struct {
int32_t index;
int32_t EOR;
} REQ_ManualDelete;
typedef struct {
int32_t EOR;
} REQ_MakeStep;
typedef struct {
int32_t EOR;
} REQ_Activity;
typedef struct {
int32_t EOR;
} REQ_Reselect;
typedef struct {
Float distance;
int32_t EOR;
} REQ_ReselectDistance;
#define REQ_SMOOTHTIME_RESET 0
#define REQ_SMOOTHTIME_ACTIVATE 1
typedef struct {
int32_t option;
int32_t EOR;
} REQ_SmoothTime;
/* ================================================== */
#define PKT_TYPE_CMD_REQUEST 1
@@ -362,7 +334,8 @@ typedef struct {
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
changed maximum number of samples in manual list to 16, new commands: modify
makestep, smoothing report, smoothtime command
*/
#define PROTO_VERSION_NUMBER 6
@@ -395,6 +368,7 @@ typedef struct {
uint32_t token; /* Command token (to prevent replay attack) */
union {
REQ_Null null;
REQ_Online online;
REQ_Offline offline;
REQ_Burst burst;
@@ -407,32 +381,23 @@ typedef struct {
REQ_Modify_Minstratum modify_minstratum;
REQ_Modify_Polltarget modify_polltarget;
REQ_Modify_Maxupdateskew modify_maxupdateskew;
REQ_Modify_Makestep modify_makestep;
REQ_Logon logon;
REQ_Settime settime;
REQ_Local local;
REQ_Manual manual;
REQ_N_Sources n_sources;
REQ_Source_Data source_data;
REQ_Rekey rekey;
REQ_Allow_Deny allow_deny;
REQ_Ac_Check ac_check;
REQ_NTP_Source ntp_source;
REQ_Del_Source del_source;
REQ_WriteRtc writertc;
REQ_Dfreq dfreq;
REQ_Doffset doffset;
REQ_Tracking tracking;
REQ_Sourcestats sourcestats;
REQ_RTCReport rtcreport;
REQ_TrimRTC trimrtc;
REQ_CycleLogs cyclelogs;
REQ_ClientAccessesByIndex client_accesses_by_index;
REQ_ManualList manual_list;
REQ_ManualDelete manual_delete;
REQ_MakeStep make_step;
REQ_Activity activity;
REQ_Reselect reselect;
REQ_ReselectDistance reselect_distance;
REQ_SmoothTime smoothtime;
} data; /* Command specific parameters */
/* The following fields only set the maximum size of the packet.
@@ -468,7 +433,8 @@ typedef struct {
#define RPY_CLIENT_ACCESSES_BY_INDEX 10
#define RPY_MANUAL_LIST 11
#define RPY_ACTIVITY 12
#define N_REPLY_TYPES 13
#define RPY_SMOOTHING 13
#define N_REPLY_TYPES 14
/* Status codes */
#define STT_SUCCESS 0
@@ -580,12 +546,6 @@ typedef struct {
int32_t EOR;
} RPY_ManualTimestamp;
typedef struct {
IPAddr ip;
uint32_t bits_specd;
uint32_t bitmap[8];
} RPY_SubnetsAccessed_Subnet;
typedef struct {
IPAddr ip;
uint32_t client_hits;
@@ -629,6 +589,19 @@ typedef struct {
int32_t EOR;
} RPY_Activity;
#define RPY_SMT_FLAG_ACTIVE 0x1
#define RPY_SMT_FLAG_LEAPONLY 0x2
typedef struct {
uint32_t flags;
Float offset;
Float freq_ppm;
Float wander_ppm;
Float last_update_ago;
Float remaining_time;
int32_t EOR;
} RPY_Smoothing;
typedef struct {
uint8_t version;
uint8_t pkt_type;
@@ -655,6 +628,7 @@ typedef struct {
RPY_ClientAccessesByIndex client_accesses_by_index;
RPY_ManualList manual_list;
RPY_Activity activity;
RPY_Smoothing smoothing;
} data; /* Reply specific parameters */
/* authentication of the packet, there is no hole after the actual data

View File

@@ -1,71 +0,0 @@
.TH CHRONY 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
.SH NAME
chrony \- programs for keeping computer clocks accurate
.SH SYNOPSIS
\fBchronyc\fR [\fIOPTIONS\fR]
\fBchronyd\fR [\fIOPTIONS\fR]
.SH DESCRIPTION
\fBchrony\fR is a pair of programs for keeping computer clocks accurate.
\fIchronyd\fR is a background (daemon) program and \fIchronyc\fR is a
command-line interface to it. Time reference sources for chronyd can be
RFC1305 NTP servers, human (via keyboard and \fIchronyc\fR), or 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 while no external
reference is present. Its use of NTP servers can be switched on and off
(through \fIchronyc\fR) to support computers with dial-up/intermittent access
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
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
accordingly. It also works out the rate at which the system clock
gains or loses time and uses this information to keep it accurate
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.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 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
reboots.
Typical accuracies available between 2 machines are
On an ethernet LAN : 100-200 microseconds, often much better
On a V32bis dial-up modem connection : 10's of milliseconds (from one
session to the next)
With a good reference clock the accuracy can reach one microsecond.
\fIchronyd\fR can also operate as an RFC1305-compatible NTP server and peer.
.SH "SEE ALSO"
.BR chronyc(1),
.BR chrony.conf(5),
.BR chronyd(8)
.I http://chrony.tuxfamily.org/
.SH AUTHOR
Richard Curnow <rc@rc0.org.uk>
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part
of "The Missing Man Pages Project". Please see
\fIhttp://www.netmeister.org/misc/m2p2/index.html\fR for details.
The complete chrony documentation is supplied in texinfo format.

View File

@@ -12,33 +12,45 @@ 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@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
for this file is \fB@SYSCONFDIR@/chrony.conf\fR. Assuming that your NTP
servers are called `foo.example.net', `bar.example.net' and `baz.example.net',
your \fBchrony.conf\fR file could contain as a minimum
server a.b.c
server d.e.f
server g.h.i
.EX
server foo.example.net
server bar.example.net
server baz.example.net
.EE
However, you will probably want to include some of the other directives
described in detail in the documentation supplied with the distribution
(\fIchrony.txt\fR and \fIchrony.texi\fR). The following directives may be
particularly useful : `driftfile', `generatecommandkey', `keyfile', `makestep'.
Also, the `iburst' server option is useful to speed up the initial
synchronization. The smallest useful configuration file would look something
like
particularly useful : `driftfile', `makestep', `rtcsync'. Also, the `iburst'
server option is useful to speed up the initial synchronization. The smallest
useful configuration file would look something like
server a.b.c iburst
server d.e.f iburst
server g.h.i iburst
keyfile @SYSCONFDIR@/chrony.keys
generatecommandkey
.EX
server foo.example.net iburst
server bar.example.net iburst
server baz.example.net iburst
driftfile @CHRONYVARDIR@/drift
makestep 10 3
rtcsync
.EE
When using a pool of NTP servers (one name is used for multiple servers which
may change over time), it's better to specify them with the `pool' directive
instead of multiple `server' directives. The configuration file could in this
case look like
.EX
pool pool.ntp.org iburst
driftfile @CHRONYVARDIR@/drift
makestep 10 3
rtcsync
.EE
.SH "SEE ALSO"
.BR chrony(1),
.BR chronyc(1),
.BR chronyd(8)

File diff suppressed because it is too large Load Diff

View File

@@ -1,73 +0,0 @@
/* Taken from /usr/include/linux/timex.h. Avoids the need to
* include kernel header files. */
#ifndef CHRONY_TIMEX_H
#define CHRONY_TIMEX_H
#include <sys/time.h>
struct timex {
unsigned int modes; /* mode selector */
long offset; /* time offset (usec) */
long freq; /* frequency offset (scaled ppm) */
long maxerror; /* maximum error (usec) */
long esterror; /* estimated error (usec) */
int status; /* clock command/status */
long constant; /* pll time constant */
long precision; /* clock precision (usec) (read only) */
long tolerance; /* clock frequency tolerance (ppm)
* (read only)
*/
struct timeval time; /* (read only) */
long tick; /* (modified) usecs between clock ticks */
long ppsfreq; /* pps frequency (scaled ppm) (ro) */
long jitter; /* pps jitter (us) (ro) */
int shift; /* interval duration (s) (shift) (ro) */
long stabil; /* pps stability (scaled ppm) (ro) */
long jitcnt; /* jitter limit exceeded (ro) */
long calcnt; /* calibration intervals (ro) */
long errcnt; /* calibration errors (ro) */
long stbcnt; /* stability limit exceeded (ro) */
int :32; int :32; int :32; int :32;
int :32; int :32; int :32; int :32;
int :32; int :32; int :32; int :32;
};
#define ADJ_OFFSET 0x0001 /* time offset */
#define ADJ_FREQUENCY 0x0002 /* frequency offset */
#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 */
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
#define SHIFT_USEC 16 /* frequency offset scale (shift) */
#define STA_PLL 0x0001 /* enable PLL updates (rw) */
#define STA_PPSFREQ 0x0002 /* enable PPS freq discipline (rw) */
#define STA_PPSTIME 0x0004 /* enable PPS time discipline (rw) */
#define STA_FLL 0x0008 /* select frequency-lock mode (rw) */
#define STA_INS 0x0010 /* insert leap (rw) */
#define STA_DEL 0x0020 /* delete leap (rw) */
#define STA_UNSYNC 0x0040 /* clock unsynchronized (rw) */
#define STA_FREQHOLD 0x0080 /* hold frequency (rw) */
#define STA_PPSSIGNAL 0x0100 /* PPS signal present (ro) */
#define STA_PPSJITTER 0x0200 /* PPS signal jitter exceeded (ro) */
#define STA_PPSWANDER 0x0400 /* PPS signal wander exceeded (ro) */
#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */
#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */
#define STA_NANO 0x2000 /* resolution (0 = us, 1 = ns) (ro) */
/* This doesn't seem to be in any include files !! */
extern int adjtimex(struct timex *);
#endif /* CHRONY_TIMEX_H */

View File

@@ -60,8 +60,7 @@ interactively.
To report bugs, please visit \fIhttp://chrony.tuxfamily.org\fR
.SH "SEE ALSO"
.BR chronyd(8),
.BR chrony(1)
.BR chronyd(8)
.I http://chrony.tuxfamily.org/

View File

@@ -70,8 +70,7 @@ option is useful if you want to stop and restart \fBchronyd\fR briefly for any
reason, e.g. to install a new version. However, it only makes sense on
systems where the kernel can maintain clock compensation whilst not under
\fBchronyd\fR's control. The only version where this happens so far is Linux.
On systems where this is not the case, e.g. Solaris and SunOS the option
should not be used.
On other systems this option should not be used.
.TP
.B \-R
When this option is used, the \fIinitstepslew\fR directive and the
@@ -135,7 +134,6 @@ To report bugs, please visit \fIhttp://chrony.tuxfamily.org/\fR
\fBchronyd\fR is documented in detail in the documentation supplied with the
distribution (\fIchrony.txt\fR and \fIchrony.texi\fR).
.BR chrony(1),
.BR chronyc(1),
.BR chrony.conf(5),
.BR hwclock(8),

257
client.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* 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
@@ -36,7 +36,6 @@
#include "getdate.h"
#include "cmdparse.h"
#include "pktlength.h"
#include "memory.h"
#include "util.h"
#ifdef FEAT_READLINE
@@ -52,7 +51,7 @@
union sockaddr_in46 {
struct sockaddr_in in4;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
struct sockaddr_in6 in6;
#endif
struct sockaddr u;
@@ -68,30 +67,6 @@ static int no_dns = 0;
static int recv_errqueue = 0;
/* ================================================== */
/* Ought to extract some code from util.c to make
a new set of utilities that can be linked into either
the daemon or the client. */
static char *
time_to_log_form(time_t t)
{
struct tm stm;
static char buffer[64];
static const char *months[] = {"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"};
stm = *gmtime(&t);
snprintf(buffer, sizeof(buffer),
"%2d%s%02d %02d:%02d:%02d",
stm.tm_mday, months[stm.tm_mon], stm.tm_year % 100,
stm.tm_hour, stm.tm_min, stm.tm_sec);
return buffer;
}
/* ================================================== */
/* Read a single line of commands from standard input. Eventually we
might want to use the GNU readline library. */
@@ -144,37 +119,26 @@ open_io(const char *hostname, int port)
int on_off = 1;
/* Note, this call could block for a while */
if (DNS_Name2IPAddress(hostname, &ip) != DNS_Success) {
if (DNS_Name2IPAddress(hostname, &ip, 1) != DNS_Success) {
fprintf(stderr, "Could not get IP address for %s\n", hostname);
exit(1);
}
memset(&his_addr, 0, sizeof (his_addr));
switch (ip.family) {
case IPADDR_INET4:
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
his_addr.in4.sin_family = AF_INET;
his_addr.in4.sin_addr.s_addr = htonl(ip.addr.in4);
his_addr.in4.sin_port = htons(port);
his_addr_len = sizeof (his_addr.in4);
break;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
case IPADDR_INET6:
sock_fd = socket(AF_INET6, SOCK_DGRAM, 0);
his_addr.in6.sin6_family = AF_INET6;
memcpy(his_addr.in6.sin6_addr.s6_addr, ip.addr.in6,
sizeof (his_addr.in6.sin6_addr.s6_addr));
his_addr.in6.sin6_port = htons(port);
his_addr_len = sizeof (his_addr.in6);
break;
#endif
default:
assert(0);
}
his_addr_len = UTI_IPAndPortToSockaddr(&ip, port, &his_addr.u);
if (sock_fd < 0) {
perror("Can't create socket");
exit(1);
@@ -187,7 +151,7 @@ open_io(const char *hostname, int port)
recv_errqueue = 1;
}
#endif
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
#ifdef IPV6_RECVERR
if (ip.family == IPADDR_INET6 &&
!setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVERR, &on_off, sizeof(on_off))) {
@@ -269,7 +233,7 @@ read_mask_address(char *line, IPAddr *mask, IPAddr *address)
}
}
} else {
if (DNS_Name2IPAddress(p, address) == DNS_Success) {
if (DNS_Name2IPAddress(p, address, 1) == DNS_Success) {
bits_to_mask(-1, address->family, mask);
return 1;
} else {
@@ -341,7 +305,7 @@ read_address_integer(char *line, IPAddr *address, int *value)
fprintf(stderr, "Invalid syntax for address value\n");
ok = 0;
} else {
if (DNS_Name2IPAddress(hostname, address) != DNS_Success) {
if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n");
ok = 0;
} else {
@@ -369,7 +333,7 @@ read_address_double(char *line, IPAddr *address, double *value)
fprintf(stderr, "Invalid syntax for address value\n");
ok = 0;
} else {
if (DNS_Name2IPAddress(hostname, address) != DNS_Success) {
if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n");
ok = 0;
} else {
@@ -676,7 +640,8 @@ process_cmd_manual(CMD_Request *msg, const char *line)
static int
parse_allow_deny(CMD_Request *msg, char *line)
{
unsigned long a, b, c, d, n;
unsigned long a, b, c, d;
int n, specified_subnet_bits;
IPAddr ip;
char *p;
@@ -693,10 +658,10 @@ parse_allow_deny(CMD_Request *msg, char *line)
n = 0;
if (!UTI_StringToIP(p, &ip) &&
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) == 0) {
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) <= 0) {
/* Try to parse as the name of a machine */
if (DNS_Name2IPAddress(p, &ip) != DNS_Success) {
if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
fprintf(stderr, "Could not read address\n");
return 0;
} else {
@@ -746,7 +711,6 @@ parse_allow_deny(CMD_Request *msg, char *line)
UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip);
if (slashpos) {
int specified_subnet_bits, n;
n = sscanf(slashpos+1, "%d", &specified_subnet_bits);
if (n == 1) {
msg->data.allow_deny.subnet_bits = htonl(specified_subnet_bits);
@@ -864,7 +828,7 @@ accheck_getaddr(char *line, IPAddr *addr)
addr->addr.in4 = (a<<24) | (b<<16) | (c<<8) | d;
return 1;
} else {
if (DNS_Name2IPAddress(p, &ip) != DNS_Success) {
if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
return 0;
} else {
*addr = ip;
@@ -966,17 +930,16 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
CPS_NTP_Source data;
CPS_Status status;
IPAddr ip_addr;
char str[64];
int result = 0;
status = CPS_ParseNTPSourceAdd(line, &data);
switch (status) {
case CPS_Success:
if (DNS_Name2IPAddress(data.name, &ip_addr) != DNS_Success) {
Free(data.name);
if (DNS_Name2IPAddress(data.name, &ip_addr, 1) != DNS_Success) {
fprintf(stderr, "Invalid host/IP address\n");
break;
}
Free(data.name);
if (data.params.min_stratum != SRC_DEFAULT_MINSTRATUM) {
fprintf(stderr, "Option minstratum not supported\n");
@@ -993,6 +956,26 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
break;
}
if (data.params.version != NTP_VERSION) {
fprintf(stderr, "Option version not supported\n");
break;
}
if (data.params.max_sources != SRC_DEFAULT_MAXSOURCES) {
fprintf(stderr, "Option maxsources not supported\n");
break;
}
if (data.params.min_samples != SRC_DEFAULT_MINSAMPLES) {
fprintf(stderr, "Option minsamples not supported\n");
break;
}
if (data.params.max_samples != SRC_DEFAULT_MAXSAMPLES) {
fprintf(stderr, "Option maxsamples not supported\n");
break;
}
msg->data.ntp_source.port = htonl((unsigned long) data.port);
UTI_IPHostToNetwork(&ip_addr, &msg->data.ntp_source.ip_addr);
msg->data.ntp_source.minpoll = htonl(data.params.minpoll);
@@ -1010,41 +993,9 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
result = 1;
break;
case CPS_BadOption:
fprintf(stderr, "Unrecognized subcommand\n");
break;
case CPS_BadHost:
fprintf(stderr, "Invalid host/IP address\n");
break;
case CPS_BadPort:
fprintf(stderr, "Unreadable port number\n");
break;
case CPS_BadMinpoll:
fprintf(stderr, "Unreadable minpoll value\n");
break;
case CPS_BadMaxpoll:
fprintf(stderr, "Unreadable maxpoll value\n");
break;
case CPS_BadPresend:
fprintf(stderr, "Unreadable presend value\n");
break;
case CPS_BadMaxdelaydevratio:
fprintf(stderr, "Unreadable max delay dev ratio value\n");
break;
case CPS_BadMaxdelayratio:
fprintf(stderr, "Unreadable max delay ratio value\n");
break;
case CPS_BadMaxdelay:
fprintf(stderr, "Unreadable max delay value\n");
break;
case CPS_BadKey:
fprintf(stderr, "Unreadable key value\n");
break;
case CPS_BadMinstratum:
fprintf(stderr, "Unreadable minstratum value\n");
break;
case CPS_BadPolltarget:
fprintf(stderr, "Unreadable polltarget value\n");
default:
CPS_StatusToString(status, str, sizeof (str));
fprintf(stderr, "%s\n", str);
break;
}
@@ -1086,7 +1037,7 @@ process_cmd_delete(CMD_Request *msg, char *line)
fprintf(stderr, "Invalid syntax for address\n");
ok = 0;
} else {
if (DNS_Name2IPAddress(hostname, &address) != DNS_Success) {
if (DNS_Name2IPAddress(hostname, &address, 1) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n");
ok = 0;
} else {
@@ -1216,7 +1167,7 @@ give_help(void)
printf("dump : Dump all measurements to save files\n");
printf("local off : Disable server capability for unsynchronised clock\n");
printf("local stratum <stratum> : Enable server capability for unsynchronised clock\n");
printf("makestep : Jump the time to remove any correction being slewed\n");
printf("makestep [<threshold> <updates>] : Correct clock by stepping\n");
printf("manual off|on|reset : Disable/enable/reset settime command and statistics\n");
printf("manual list : Show previous settime entries\n");
printf("maxdelay <address> <new-max-delay> : Modify maximum round-trip valid sample delay for source\n");
@@ -1233,6 +1184,8 @@ give_help(void)
printf("reselect : Reselect synchronisation source\n");
printf("rtcdata : Print current RTC performance parameters\n");
printf("settime <date/time (e.g. Nov 21, 1997 16:30:05 or 16:30:05)> : Manually set the daemon time\n");
printf("smoothing : Display current time smoothing state\n");
printf("smoothtime reset|activate : Reset/activate time smoothing\n");
printf("sources [-v] : Display information about current sources\n");
printf("sourcestats [-v] : Display estimation information about current sources\n");
printf("tracking : Display system time information\n");
@@ -1412,7 +1365,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
(where_from.u.sa_family == AF_INET &&
(where_from.in4.sin_addr.s_addr != his_addr.in4.sin_addr.s_addr ||
where_from.in4.sin_port != his_addr.in4.sin_port)) ||
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
(where_from.u.sa_family == AF_INET6 &&
(memcmp(where_from.in6.sin6_addr.s6_addr, his_addr.in6.sin6_addr.s6_addr,
sizeof (where_from.in6.sin6_addr.s6_addr)) != 0 ||
@@ -1750,10 +1703,10 @@ process_cmd_sources(char *line)
printf(" / .- Source state '*' = current synced, '+' = combined , '-' = not combined,\n");
printf("| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.\n");
printf("|| .- xxxx [ yyyy ] +/- zzzz\n");
printf("|| / xxxx = adjusted offset,\n");
printf("|| Log2(Polling interval) -. | yyyy = measured offset,\n");
printf("|| \\ | zzzz = estimated error.\n");
printf("|| | | \n");
printf("|| Reachability register (octal) -. | xxxx = adjusted offset,\n");
printf("|| Log2(Polling interval) --. | | yyyy = measured offset,\n");
printf("|| \\ | | zzzz = estimated error.\n");
printf("|| | | \\\n");
}
printf("MS Name/IP address Stratum Poll Reach LastRx Last sample\n");
@@ -2013,6 +1966,63 @@ process_cmd_tracking(char *line)
}
/* ================================================== */
static int
process_cmd_smoothing(char *line)
{
CMD_Request request;
CMD_Reply reply;
uint32_t flags;
double offset;
double freq_ppm;
double wander_ppm;
double last_update_ago;
double remaining_time;
request.command = htons(REQ_SMOOTHING);
if (request_reply(&request, &reply, RPY_SMOOTHING, 0)) {
flags = ntohl(reply.data.smoothing.flags);
offset = UTI_FloatNetworkToHost(reply.data.smoothing.offset);
freq_ppm = UTI_FloatNetworkToHost(reply.data.smoothing.freq_ppm);
wander_ppm = UTI_FloatNetworkToHost(reply.data.smoothing.wander_ppm);
last_update_ago = UTI_FloatNetworkToHost(reply.data.smoothing.last_update_ago);
remaining_time = UTI_FloatNetworkToHost(reply.data.smoothing.remaining_time);
printf("Active : %s%s\n",
flags & RPY_SMT_FLAG_ACTIVE ? "Yes" : "No",
flags & RPY_SMT_FLAG_LEAPONLY ? " (leap second only)" : "");
printf("Offset : %+.9f seconds\n", offset);
printf("Frequency : %+.6f ppm\n", freq_ppm);
printf("Wander : %+.6f ppm per second\n", wander_ppm);
printf("Last update : %.1f seconds ago\n", last_update_ago);
printf("Remaining time : %.1f seconds\n", remaining_time);
return 1;
}
return 0;
}
/* ================================================== */
static int
process_cmd_smoothtime(CMD_Request *msg, const char *line)
{
if (!strcmp(line, "reset")) {
msg->data.smoothtime.option = htonl(REQ_SMOOTHTIME_RESET);
} else if (!strcmp(line, "activate")) {
msg->data.smoothtime.option = htonl(REQ_SMOOTHTIME_ACTIVATE);
} else {
fprintf(stderr, "Invalid syntax for smoothtime command\n");
return 0;
}
msg->command = htons(REQ_SMOOTHTIME);
return 1;
}
/* ================================================== */
static int
process_cmd_rtcreport(char *line)
{
@@ -2157,15 +2167,15 @@ process_cmd_manual_list(const char *line)
if (request_reply(&request, &reply, RPY_MANUAL_LIST, 0)) {
n_samples = ntohl(reply.data.manual_list.n_samples);
printf("210 n_samples = %d\n", n_samples);
printf("# Date Time(UTC) Slewed Original Residual\n"
"====================================================\n");
printf("# Date Time(UTC) Slewed Original Residual\n"
"=======================================================\n");
for (i=0; i<n_samples; i++) {
sample = &reply.data.manual_list.samples[i];
UTI_TimevalNetworkToHost(&sample->when, &when);
slewed_offset = UTI_FloatNetworkToHost(sample->slewed_offset);
orig_offset = UTI_FloatNetworkToHost(sample->orig_offset);
residual = UTI_FloatNetworkToHost(sample->residual);
printf("%2d %s %10.2f %10.2f %10.2f\n", i, time_to_log_form(when.tv_sec), slewed_offset, orig_offset, residual);
printf("%2d %s %10.2f %10.2f %10.2f\n", i, UTI_TimeToLogForm(when.tv_sec), slewed_offset, orig_offset, residual);
}
return 1;
}
@@ -2236,10 +2246,25 @@ process_cmd_rekey(CMD_Request *msg, char *line)
/* ================================================== */
static void
static int
process_cmd_makestep(CMD_Request *msg, char *line)
{
msg->command = htons(REQ_MAKESTEP);
int limit;
double threshold;
if (*line) {
if (sscanf(line, "%lf %d", &threshold, &limit) != 2) {
fprintf(stderr, "Bad syntax for makestep command\n");
return 0;
}
msg->command = htons(REQ_MODIFY_MAKESTEP);
msg->data.modify_makestep.limit = htonl(limit);
msg->data.modify_makestep.threshold = UTI_FloatHostToNetwork(threshold);
} else {
msg->command = htons(REQ_MAKESTEP);
}
return 1;
}
/* ================================================== */
@@ -2518,7 +2543,7 @@ process_line(char *line, int *quit)
} else if (!strcmp(command, "local")) {
do_normal_submit = process_cmd_local(&tx_message, line);
} else if (!strcmp(command, "makestep")) {
process_cmd_makestep(&tx_message, line);
do_normal_submit = process_cmd_makestep(&tx_message, line);
} else if (!strcmp(command, "manual")) {
if (!strncmp(line, "list", 4)) {
do_normal_submit = 0;
@@ -2569,6 +2594,11 @@ process_line(char *line, int *quit)
} else if (!strcmp(command, "settime")) {
do_normal_submit = 0;
ret = process_cmd_settime(line);
} else if (!strcmp(command, "smoothing")) {
do_normal_submit = 0;
ret = process_cmd_smoothing(line);
} else if (!strcmp(command, "smoothtime")) {
do_normal_submit = process_cmd_smoothtime(&tx_message, line);
} else if (!strcmp(command, "sources")) {
do_normal_submit = 0;
ret = process_cmd_sources(line);
@@ -2610,8 +2640,8 @@ authenticate_from_config(const char *filename)
CMD_Reply rx_message;
char line[2048], keyfile[2048], *command, *arg, *password;
const char *hashname;
unsigned long key_id = 0, key_id2 = -1;
int ret;
uint32_t key_id = 0, key_id2;
int key_id_valid = 1, ret;
FILE *in;
in = fopen(filename, "r");
@@ -2628,13 +2658,12 @@ authenticate_from_config(const char *filename)
if (!strcasecmp(command, "keyfile")) {
snprintf(keyfile, sizeof (keyfile), "%s", arg);
} else if (!strcasecmp(command, "commandkey")) {
if (sscanf(arg, "%lu", &key_id) != 1)
key_id = -1;
key_id_valid = sscanf(arg, "%"SCNu32, &key_id) == 1;
}
}
fclose(in);
if (!*keyfile || key_id == -1) {
if (!*keyfile || !key_id_valid) {
fprintf(stderr, "Could not read keyfile or commandkey in file %s\n", filename);
return 0;
}
@@ -2645,6 +2674,7 @@ authenticate_from_config(const char *filename)
return 0;
}
key_id2 = key_id + 1;
while (fgets(line, sizeof (line), in)) {
CPS_NormalizeLine(line);
if (!*line || !CPS_ParseKey(line, &key_id2, &hashname, &password))
@@ -2662,7 +2692,7 @@ authenticate_from_config(const char *filename)
ret = 0;
}
} else {
fprintf(stderr, "Could not find key %lu in keyfile %s\n", key_id, keyfile);
fprintf(stderr, "Could not find key %"PRIu32" in keyfile %s\n", key_id, keyfile);
ret = 0;
}
@@ -2715,7 +2745,7 @@ static void
display_gpl(void)
{
printf("chrony version %s\n"
"Copyright (C) 1997-2003, 2007, 2009-2014 Richard P. Curnow and others\n"
"Copyright (C) 1997-2003, 2007, 2009-2015 Richard P. Curnow and others\n"
"chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n"
"you are welcome to redistribute it under certain conditions. See the\n"
"GNU General Public License version 2 for details.\n\n",
@@ -2762,11 +2792,12 @@ main(int argc, char **argv)
} else if (!strcmp(*argv, "-6")) {
family = IPADDR_INET6;
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
printf("chronyc (chrony) version %s\n", CHRONY_VERSION);
exit(0);
printf("chronyc (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYC_FEATURES);
return 0;
} else if (!strncmp(*argv, "-", 1)) {
fprintf(stderr, "Usage : %s [-h <hostname>] [-p <port-number>] [-n] [-4|-6] [-m] [-a] [-f <file>]] [command]\n", progname);
exit(1);
fprintf(stderr, "Usage: %s [-h HOST] [-p PORT] [-n] [-4|-6] [-a] [-f FILE] [-m] [COMMAND]\n",
progname);
return 1;
} else {
break; /* And process remainder of line as a command */
}

View File

@@ -174,6 +174,11 @@ CLG_Initialise(void)
void
CLG_Finalise(void)
{
int i;
for (i = 0; i < n_nodes; i++)
Free(nodes[i]);
Free(nodes);
}
/* ================================================== */
@@ -256,31 +261,6 @@ find_subnet(Subnet *subnet, uint32_t *addr, int addr_len, int bits_consumed)
}
}
/* ================================================== */
/* Search for the record for a particular subnet, but return NULL if
one of the parents does not exist - never open a node out */
static void *
find_subnet_dont_open(Subnet *subnet, uint32_t *addr, int addr_len, int bits_consumed)
{
uint32_t this_subnet;
if (bits_consumed >= 32 * addr_len) {
return subnet;
} else {
this_subnet = get_subnet(addr, bits_consumed);
bits_consumed += NBITS;
if (!subnet->entry[this_subnet]) {
return NULL;
} else {
return find_subnet_dont_open((Subnet *) subnet->entry[this_subnet], addr, addr_len, bits_consumed);
}
}
}
/* ================================================== */
void
@@ -386,95 +366,6 @@ CLG_LogCommandAccess(IPAddr *client, CLG_Command_Type type, time_t now)
/* ================================================== */
CLG_Status
CLG_GetSubnetBitmap(IPAddr *subnet, int bits, CLG_Bitmap result)
{
Subnet *s;
uint32_t ip6[4];
unsigned long i;
unsigned long word, bit, mask;
if (bits >= 0 && bits % 8 == 0) {
memset (result, 0, TABLE_SIZE/8);
if (active) {
switch (subnet->family) {
case IPADDR_INET4:
if (bits >= 32)
return CLG_BADSUBNET;
s = find_subnet_dont_open(&top_subnet4, &subnet->addr.in4, 1, 32 - bits);
break;
case IPADDR_INET6:
if (bits >= 128)
return CLG_BADSUBNET;
split_ip6(subnet, ip6);
s = find_subnet_dont_open(&top_subnet6, ip6, 4, 128 - bits);
break;
default:
return CLG_BADSUBNET;
}
if (s) {
for (i=0; i<256; i++) {
if (s->entry[i]) {
word = i / 32;
bit = i % 32;
mask = 1UL << bit;
result[word] |= mask;
}
}
return CLG_SUCCESS;
} else {
return CLG_EMPTYSUBNET;
}
} else {
return CLG_INACTIVE;
}
} else {
return CLG_BADSUBNET;
}
}
/* ================================================== */
CLG_Status
CLG_GetClientAccessReportByIP(IPAddr *ip, RPT_ClientAccess_Report *report, time_t now)
{
uint32_t ip6[4];
Node *node;
if (!active) {
return CLG_INACTIVE;
} else {
switch (ip->family) {
case IPADDR_INET4:
node = (Node *) find_subnet_dont_open(&top_subnet4, &ip->addr.in4, 1, 0);
break;
case IPADDR_INET6:
split_ip6(ip, ip6);
node = (Node *) find_subnet_dont_open(&top_subnet6, ip6, 4, 0);
break;
default:
return CLG_EMPTYSUBNET;
}
if (!node) {
return CLG_EMPTYSUBNET;
} else {
report->client_hits = node->client_hits;
report->peer_hits = node->peer_hits;
report->cmd_hits_auth = node->cmd_hits_auth;
report->cmd_hits_normal = node->cmd_hits_normal;
report->cmd_hits_bad = node->cmd_hits_bad;
report->last_ntp_hit_ago = now - node->last_ntp_hit;
report->last_cmd_hit_ago = now - node->last_cmd_hit;
return CLG_SUCCESS;
}
}
}
/* ================================================== */
CLG_Status
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report,
time_t now, unsigned long *n_indices)

View File

@@ -31,9 +31,6 @@
#include "sysincl.h"
#include "reports.h"
/* Enough to hold flags for 256 hosts in a class C */
typedef uint32_t CLG_Bitmap[8];
extern void CLG_Initialise(void);
extern void CLG_Finalise(void);
extern void CLG_LogNTPClientAccess(IPAddr *client, time_t now);
@@ -60,26 +57,8 @@ typedef enum {
CLG_INDEXTOOLARGE /* Node index is higher than number of nodes present */
} CLG_Status;
/* For bits=0, 8, 16, flag which immediate subnets of that subnet are
known. For bits=24, flag which hosts in that subnet are known.
Other values, return 0 (failed) */
extern CLG_Status CLG_GetSubnetBitmap(IPAddr *subnet, int bits, CLG_Bitmap result);
extern CLG_Status
CLG_GetClientAccessReportByIP(IPAddr *ip, RPT_ClientAccess_Report *report, time_t now);
CLG_Status
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report,
time_t now, unsigned long *n_indices);
/* And an iterating function, to call 'fn' for each client or peer
that has accessed us since 'since'. */
extern void CLG_IterateNTPClients
(void (*fn)(IPAddr *client, void *arb),
void *arb,
time_t since);
#endif /* GOT_CLIENTLOG_H */

481
cmdmon.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* 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
@@ -37,6 +37,7 @@
#include "keys.h"
#include "ntp_sources.h"
#include "ntp_core.h"
#include "smooth.h"
#include "sources.h"
#include "sourcestats.h"
#include "reference.h"
@@ -54,7 +55,7 @@
union sockaddr_in46 {
struct sockaddr_in in4;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
struct sockaddr_in6 in6;
#endif
struct sockaddr u;
@@ -62,7 +63,7 @@ union sockaddr_in46 {
/* File descriptors for command and monitoring sockets */
static int sock_fd4;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
static int sock_fd6;
#endif
@@ -110,7 +111,7 @@ static ResponseCell *free_replies;
/* ================================================== */
/* Array of permission levels for command types */
static int permissions[] = {
static const char permissions[] = {
PERMIT_OPEN, /* NULL */
PERMIT_AUTH, /* ONLINE */
PERMIT_AUTH, /* OFFLINE */
@@ -160,7 +161,10 @@ static int permissions[] = {
PERMIT_AUTH, /* MODIFY_POLLTARGET */
PERMIT_AUTH, /* MODIFY_MAXDELAYDEVRATIO */
PERMIT_AUTH, /* RESELECT */
PERMIT_AUTH /* RESELECTDISTANCE */
PERMIT_AUTH, /* RESELECTDISTANCE */
PERMIT_AUTH, /* MODIFY_MAKESTEP */
PERMIT_OPEN, /* SMOOTHING */
PERMIT_AUTH, /* SMOOTHTIME */
};
/* ================================================== */
@@ -207,7 +211,7 @@ prepare_socket(int family, int port_number)
}
#endif
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
if (family == AF_INET6) {
#ifdef IPV6_V6ONLY
/* Receive IPv6 packets only */
@@ -231,9 +235,9 @@ prepare_socket(int family, int port_number)
if (bind_address.family == IPADDR_INET4)
my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4);
else
my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
my_addr.in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
break;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
case AF_INET6:
my_addr_len = sizeof (my_addr.in6);
my_addr.in6.sin6_family = family;
@@ -245,7 +249,7 @@ prepare_socket(int family, int port_number)
memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6,
sizeof (my_addr.in6.sin6_addr.s6_addr));
else
my_addr.in6.sin6_addr = in6addr_any;
my_addr.in6.sin6_addr = in6addr_loopback;
break;
#endif
default:
@@ -304,7 +308,7 @@ CAM_Initialise(int family)
sock_fd4 = prepare_socket(AF_INET, port_number);
else
sock_fd4 = -1;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
if (port_number && (family == IPADDR_UNSPEC || family == IPADDR_INET6))
sock_fd6 = prepare_socket(AF_INET6, port_number);
else
@@ -312,7 +316,7 @@ CAM_Initialise(int family)
#endif
if (port_number && sock_fd4 < 0
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
&& sock_fd6 < 0
#endif
) {
@@ -333,7 +337,7 @@ CAM_Finalise(void)
close(sock_fd4);
}
sock_fd4 = -1;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
if (sock_fd6 >= 0) {
SCH_RemoveInputFileHandler(sock_fd6);
close(sock_fd6);
@@ -553,7 +557,7 @@ ts_is_unique_and_not_stale(struct timeval *ts, struct timeval *now)
/* ================================================== */
#define REPLY_EXTEND_QUANTUM 32
#define REPLY_EXTEND_QUANTUM 8
static void
get_more_replies(void)
@@ -566,6 +570,7 @@ get_more_replies(void)
for (i=1; i<REPLY_EXTEND_QUANTUM; i++) {
new_replies[i-1].next = new_replies + i;
}
new_replies[REPLY_EXTEND_QUANTUM - 1].next = NULL;
free_replies = new_replies;
}
}
@@ -687,7 +692,7 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
sock_fd = sock_fd4;
addrlen = sizeof (where_to->in4);
break;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
case AF_INET6:
sock_fd = sock_fd6;
addrlen = sizeof (where_to->in6);
@@ -705,34 +710,17 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
unsigned short port;
IPAddr ip;
switch (where_to->u.sa_family) {
case AF_INET:
ip.family = IPADDR_INET4;
ip.addr.in4 = ntohl(where_to->in4.sin_addr.s_addr);
port = ntohs(where_to->in4.sin_port);
break;
#ifdef HAVE_IPV6
case AF_INET6:
ip.family = IPADDR_INET6;
memcpy(ip.addr.in6, (where_to->in6.sin6_addr.s6_addr), sizeof(ip.addr.in6));
port = ntohs(where_to->in6.sin6_port);
break;
#endif
default:
assert(0);
}
UTI_SockaddrToIPAndPort(&where_to->u, &ip, &port);
DEBUG_LOG(LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&ip), port);
}
}
/* ================================================== */
static void
handle_null(CMD_Request *rx_message, CMD_Reply *tx_message)
handle_dump(CMD_Request *rx_message, CMD_Reply *tx_message)
{
tx_message->status = htons(STT_SUCCESS);
SRC_DumpSources();
}
/* ================================================== */
@@ -740,16 +728,12 @@ handle_null(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_online(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address, mask;
UTI_IPNetworkToHost(&rx_message->data.online.mask, &mask);
UTI_IPNetworkToHost(&rx_message->data.online.address, &address);
status = NSR_TakeSourcesOnline(&mask, &address);
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_TakeSourcesOnline(&mask, &address))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -757,16 +741,12 @@ handle_online(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_offline(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address, mask;
UTI_IPNetworkToHost(&rx_message->data.offline.mask, &mask);
UTI_IPNetworkToHost(&rx_message->data.offline.address, &address);
status = NSR_TakeSourcesOffline(&mask, &address);
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_TakeSourcesOffline(&mask, &address))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -774,19 +754,14 @@ handle_offline(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_burst(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address, mask;
UTI_IPNetworkToHost(&rx_message->data.burst.mask, &mask);
UTI_IPNetworkToHost(&rx_message->data.burst.address, &address);
status = NSR_InitiateSampleBurst(ntohl(rx_message->data.burst.n_good_samples),
ntohl(rx_message->data.burst.n_total_samples),
&mask, &address);
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_InitiateSampleBurst(ntohl(rx_message->data.burst.n_good_samples),
ntohl(rx_message->data.burst.n_total_samples),
&mask, &address))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -794,17 +769,12 @@ handle_burst(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_minpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
status = NSR_ModifyMinpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMinpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -812,17 +782,12 @@ handle_modify_minpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
status = NSR_ModifyMaxpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -830,16 +795,12 @@ handle_modify_maxpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelay.address, &address);
status = NSR_ModifyMaxdelay(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelay.new_max_delay));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxdelay(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelay.new_max_delay)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -847,16 +808,12 @@ handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelayratio.address, &address);
status = NSR_ModifyMaxdelayratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelayratio.new_max_delay_ratio));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxdelayratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelayratio.new_max_delay_ratio)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -864,16 +821,12 @@ handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxdelaydevratio(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelaydevratio.address, &address);
status = NSR_ModifyMaxdelaydevratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelaydevratio.new_max_delay_dev_ratio));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxdelaydevratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelaydevratio.new_max_delay_dev_ratio)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -881,17 +834,12 @@ handle_modify_maxdelaydevratio(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_minstratum(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
status = NSR_ModifyMinstratum(&address,
ntohl(rx_message->data.modify_minstratum.new_min_stratum));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMinstratum(&address,
ntohl(rx_message->data.modify_minstratum.new_min_stratum)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -899,17 +847,12 @@ handle_modify_minstratum(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_polltarget(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_polltarget.address, &address);
status = NSR_ModifyPolltarget(&address,
ntohl(rx_message->data.modify_polltarget.new_poll_target));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyPolltarget(&address,
ntohl(rx_message->data.modify_polltarget.new_poll_target)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -918,7 +861,15 @@ static void
handle_modify_maxupdateskew(CMD_Request *rx_message, CMD_Reply *tx_message)
{
REF_ModifyMaxupdateskew(UTI_FloatNetworkToHost(rx_message->data.modify_maxupdateskew.new_max_update_skew));
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
static void
handle_modify_makestep(CMD_Request *rx_message, CMD_Reply *tx_message)
{
REF_ModifyMakestep(ntohl(rx_message->data.modify_makestep.limit),
UTI_FloatNetworkToHost(rx_message->data.modify_makestep.threshold));
}
/* ================================================== */
@@ -930,14 +881,15 @@ handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message)
long offset_cs;
double dfreq_ppm, new_afreq_ppm;
UTI_TimevalNetworkToHost(&rx_message->data.settime.ts, &ts);
if (MNL_AcceptTimestamp(&ts, &offset_cs, &dfreq_ppm, &new_afreq_ppm)) {
tx_message->status = htons(STT_SUCCESS);
if (!MNL_IsEnabled()) {
tx_message->status = htons(STT_NOTENABLED);
} else if (MNL_AcceptTimestamp(&ts, &offset_cs, &dfreq_ppm, &new_afreq_ppm)) {
tx_message->reply = htons(RPY_MANUAL_TIMESTAMP);
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 {
tx_message->status = htons(STT_NOTENABLED);
tx_message->status = htons(STT_FAILED);
}
}
@@ -954,7 +906,6 @@ handle_local(CMD_Request *rx_message, CMD_Reply *tx_message)
} else {
REF_DisableLocal();
}
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -974,8 +925,10 @@ handle_manual(CMD_Request *rx_message, CMD_Reply *tx_message)
case 2:
MNL_Reset();
break;
default:
tx_message->status = htons(STT_INVALID);
break;
}
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -985,7 +938,6 @@ handle_n_sources(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int n_sources;
n_sources = SRC_ReadNumberOfSources();
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_N_SOURCES);
tx_message->data.n_sources.n_sources = htonl(n_sources);
}
@@ -999,7 +951,7 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
struct timeval now_corr;
/* Get data */
LCL_ReadCookedTime(&now_corr, NULL);
SCH_GetLastEventTime(&now_corr, NULL, NULL);
if (SRC_ReportSource(ntohl(rx_message->data.source_data.index), &report, &now_corr)) {
switch (SRC_GetType(ntohl(rx_message->data.source_data.index))) {
case SRC_NTP:
@@ -1010,7 +962,6 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
break;
}
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_SOURCE_DATA);
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.source_data.ip_addr);
@@ -1055,7 +1006,7 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
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);
tx_message->data.source_data.flags = htons(RPY_SD_FLAG_NOSELECT);
break;
}
tx_message->data.source_data.reachability = htons(report.reachability);
@@ -1073,136 +1024,35 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_rekey(CMD_Request *rx_message, CMD_Reply *tx_message)
{
tx_message->status = htons(STT_SUCCESS);
KEY_Reload();
}
/* ================================================== */
static void
handle_allow(CMD_Request *rx_message, CMD_Reply *tx_message)
handle_allowdeny(CMD_Request *rx_message, CMD_Reply *tx_message, int allow, int all)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 1, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NCR_AddAccessRestriction(&ip, subnet_bits, allow, all))
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_allowall(CMD_Request *rx_message, CMD_Reply *tx_message)
handle_cmdallowdeny(CMD_Request *rx_message, CMD_Reply *tx_message, int allow, int all)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 1, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!CAM_AddAccessRestriction(&ip, subnet_bits, allow, all))
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_deny(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 0, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_denyall(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 0, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmdallow(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 1, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmdallowall(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 1, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmddeny(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 0, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmddenyall(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 0, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
@@ -1260,11 +1110,14 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m
params.min_stratum = SRC_DEFAULT_MINSTRATUM;
params.poll_target = SRC_DEFAULT_POLLTARGET;
params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
params.version = NTP_VERSION;
params.max_sources = SRC_DEFAULT_MAXSOURCES;
params.min_samples = SRC_DEFAULT_MINSAMPLES;
params.max_samples = SRC_DEFAULT_MAXSAMPLES;
status = NSR_AddSource(&rem_addr, type, &params);
switch (status) {
case NSR_Success:
tx_message->status = htons(STT_SUCCESS);
break;
case NSR_AlreadyInUse:
tx_message->status = htons(STT_SOURCEALREADYKNOWN);
@@ -1295,7 +1148,6 @@ handle_del_source(CMD_Request *rx_message, CMD_Reply *tx_message)
status = NSR_RemoveSource(&rem_addr);
switch (status) {
case NSR_Success:
tx_message->status = htons(STT_SUCCESS);
break;
case NSR_NoSuchSource:
tx_message->status = htons(STT_NOSUCHSOURCE);
@@ -1315,7 +1167,6 @@ handle_writertc(CMD_Request *rx_message, CMD_Reply *tx_message)
{
switch (RTC_WriteParameters()) {
case RTC_ST_OK:
tx_message->status = htons(STT_SUCCESS);
break;
case RTC_ST_NODRV:
tx_message->status = htons(STT_NORTC);
@@ -1335,7 +1186,6 @@ handle_dfreq(CMD_Request *rx_message, CMD_Reply *tx_message)
dfreq = UTI_FloatNetworkToHost(rx_message->data.dfreq.dfreq);
LCL_AccumulateDeltaFrequency(dfreq * 1.0e-6);
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta freq of %.3fppm", dfreq);
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1350,7 +1200,6 @@ handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
doffset = (double) sec + 1.0e-6 * (double) usec;
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset);
LCL_AccumulateOffset(doffset, 0.0);
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1361,7 +1210,6 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
RPT_TrackingReport rpt;
REF_GetTrackingReport(&rpt);
tx_message->status = htons(STT_SUCCESS);
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);
@@ -1381,6 +1229,60 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
/* ================================================== */
static void
handle_smoothing(CMD_Request *rx_message, CMD_Reply *tx_message)
{
RPT_SmoothingReport report;
struct timeval now;
SCH_GetLastEventTime(&now, NULL, NULL);
if (!SMT_GetSmoothingReport(&report, &now)) {
tx_message->status = htons(STT_NOTENABLED);
return;
}
tx_message->reply = htons(RPY_SMOOTHING);
tx_message->data.smoothing.flags = htonl((report.active ? RPY_SMT_FLAG_ACTIVE : 0) |
(report.leap_only ? RPY_SMT_FLAG_LEAPONLY : 0));
tx_message->data.smoothing.offset = UTI_FloatHostToNetwork(report.offset);
tx_message->data.smoothing.freq_ppm = UTI_FloatHostToNetwork(report.freq_ppm);
tx_message->data.smoothing.wander_ppm = UTI_FloatHostToNetwork(report.wander_ppm);
tx_message->data.smoothing.last_update_ago = UTI_FloatHostToNetwork(report.last_update_ago);
tx_message->data.smoothing.remaining_time = UTI_FloatHostToNetwork(report.remaining_time);
}
/* ================================================== */
static void
handle_smoothtime(CMD_Request *rx_message, CMD_Reply *tx_message)
{
struct timeval now;
int option;
if (!SMT_IsEnabled()) {
tx_message->status = htons(STT_NOTENABLED);
return;
}
option = ntohl(rx_message->data.smoothtime.option);
SCH_GetLastEventTime(&now, NULL, NULL);
switch (option) {
case REQ_SMOOTHTIME_RESET:
SMT_Reset(&now);
break;
case REQ_SMOOTHTIME_ACTIVATE:
SMT_Activate(&now);
break;
default:
tx_message->status = htons(STT_INVALID);
break;
}
}
/* ================================================== */
static void
handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message)
{
@@ -1388,12 +1290,11 @@ handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message)
RPT_SourcestatsReport report;
struct timeval now_corr;
LCL_ReadCookedTime(&now_corr, NULL);
SCH_GetLastEventTime(&now_corr, NULL, NULL);
status = SRC_ReportSourcestats(ntohl(rx_message->data.sourcestats.index),
&report, &now_corr);
if (status) {
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_SOURCESTATS);
tx_message->data.sourcestats.ref_id = htonl(report.ref_id);
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.sourcestats.ip_addr);
@@ -1419,7 +1320,6 @@ handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message)
RPT_RTC_Report report;
status = RTC_GetReport(&report);
if (status) {
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_RTC);
UTI_TimevalHostToNetwork(&report.ref_time, &tx_message->data.rtc.ref_time);
tx_message->data.rtc.n_samples = htons(report.n_samples);
@@ -1437,13 +1337,8 @@ handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_trimrtc(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
status = RTC_Trim();
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!RTC_Trim())
tx_message->status = htons(STT_NORTC);
}
}
/* ================================================== */
@@ -1452,8 +1347,6 @@ static void
handle_cyclelogs(CMD_Request *rx_message, CMD_Reply *tx_message)
{
LOG_CycleLogFiles();
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1463,24 +1356,22 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
{
CLG_Status result;
RPT_ClientAccessByIndex_Report report;
unsigned long first_index, n_indices, last_index, n_indices_in_table;
unsigned long first_index, n_indices, n_indices_in_table;
int i, j;
struct timeval now;
LCL_ReadCookedTime(&now, NULL);
SCH_GetLastEventTime(&now, NULL, NULL);
first_index = ntohl(rx_message->data.client_accesses_by_index.first_index);
n_indices = ntohl(rx_message->data.client_accesses_by_index.n_indices);
last_index = first_index + n_indices - 1;
if (n_indices > MAX_CLIENT_ACCESSES)
n_indices = MAX_CLIENT_ACCESSES;
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX);
for (i = first_index, j = 0;
(i <= last_index) && (j < MAX_CLIENT_ACCESSES);
i++) {
result = CLG_GetClientAccessReportByIndex(i, &report, now.tv_sec, &n_indices_in_table);
for (i = 0, j = 0; i < n_indices; i++) {
result = CLG_GetClientAccessReportByIndex(first_index + i, &report,
now.tv_sec, &n_indices_in_table);
tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices_in_table);
switch (result) {
@@ -1506,7 +1397,7 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
}
}
tx_message->data.client_accesses_by_index.next_index = htonl(i);
tx_message->data.client_accesses_by_index.next_index = htonl(first_index + i);
tx_message->data.client_accesses_by_index.n_clients = htonl(j);
}
@@ -1520,7 +1411,6 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
RPY_ManualListSample *sample;
RPT_ManualSamplesReport report[MAX_MANUAL_LIST_SAMPLES];
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_MANUAL_LIST);
MNL_ReportSamples(report, MAX_MANUAL_LIST_SAMPLES, &n_samples);
@@ -1539,16 +1429,11 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
int index;
index = ntohl(rx_message->data.manual_delete.index);
status = MNL_DeleteSample(index);
if (!status) {
if (!MNL_DeleteSample(index))
tx_message->status = htons(STT_BADSAMPLE);
} else {
tx_message->status = htons(STT_SUCCESS);
}
}
/* ================================================== */
@@ -1556,8 +1441,8 @@ handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message)
{
LCL_MakeStep();
tx_message->status = htons(STT_SUCCESS);
if (!LCL_MakeStep())
tx_message->status = htons(STT_FAILED);
}
/* ================================================== */
@@ -1572,7 +1457,6 @@ handle_activity(CMD_Request *rx_message, CMD_Reply *tx_message)
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);
}
@@ -1584,7 +1468,6 @@ handle_reselect_distance(CMD_Request *rx_message, CMD_Reply *tx_message)
double dist;
dist = UTI_FloatNetworkToHost(rx_message->data.reselect_distance.distance);
SRC_SetReselectDistance(dist);
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1593,7 +1476,6 @@ static void
handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
{
SRC_ReselectSource();
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1649,27 +1531,20 @@ read_from_cmd_socket(void *anything)
read_length = status;
LCL_ReadRawTime(&now);
LCL_CookTime(&now, &cooked_now, NULL);
/* Get current time cheaply */
SCH_GetLastEventTime(&cooked_now, NULL, &now);
switch (where_from.u.sa_family) {
case AF_INET:
remote_ip.family = IPADDR_INET4;
remote_ip.addr.in4 = ntohl(where_from.in4.sin_addr.s_addr);
remote_port = ntohs(where_from.in4.sin_port);
localhost = (remote_ip.addr.in4 == 0x7f000001UL);
UTI_SockaddrToIPAndPort(&where_from.u, &remote_ip, &remote_port);
/* Check if it's a loopback address (127.0.0.1 or ::1) */
switch (remote_ip.family) {
case IPADDR_INET4:
localhost = remote_ip.addr.in4 == INADDR_LOOPBACK;
break;
#ifdef HAVE_IPV6
case AF_INET6:
remote_ip.family = IPADDR_INET6;
memcpy(&remote_ip.addr.in6, where_from.in6.sin6_addr.s6_addr,
sizeof (remote_ip.addr.in6));
remote_port = ntohs(where_from.in6.sin6_port);
/* Check for ::1 */
for (localhost = 0; localhost < 16; localhost++)
if (remote_ip.addr.in6[localhost] != 0)
break;
localhost = (localhost == 15 && remote_ip.addr.in6[localhost] == 1);
#ifdef FEAT_IPV6
case IPADDR_INET6:
localhost = !memcmp(remote_ip.addr.in6, &in6addr_loopback,
sizeof (in6addr_loopback));
break;
#endif
default:
@@ -1712,6 +1587,7 @@ read_from_cmd_socket(void *anything)
tx_message.command = rx_message.command;
tx_message.sequence = rx_message.sequence;
tx_message.reply = htons(RPY_NULL);
tx_message.status = htons(STT_SUCCESS);
tx_message.pad1 = 0;
tx_message.pad2 = 0;
tx_message.pad3 = 0;
@@ -1912,7 +1788,11 @@ read_from_cmd_socket(void *anything)
if (allowed) {
switch(rx_command) {
case REQ_NULL:
handle_null(&rx_message, &tx_message);
/* Do nothing */
break;
case REQ_DUMP:
handle_dump(&rx_message, &tx_message);
break;
case REQ_ONLINE:
@@ -1935,11 +1815,6 @@ read_from_cmd_socket(void *anything)
handle_modify_maxpoll(&rx_message, &tx_message);
break;
case REQ_DUMP:
SRC_DumpSources();
tx_message.status = htons(STT_SUCCESS);
break;
case REQ_MODIFY_MAXDELAY:
handle_modify_maxdelay(&rx_message, &tx_message);
break;
@@ -1956,6 +1831,10 @@ read_from_cmd_socket(void *anything)
handle_modify_maxupdateskew(&rx_message, &tx_message);
break;
case REQ_MODIFY_MAKESTEP:
handle_modify_makestep(&rx_message, &tx_message);
break;
case REQ_LOGON:
/* If the log-on fails, record the reason why */
if (!issue_token) {
@@ -2003,35 +1882,35 @@ read_from_cmd_socket(void *anything)
break;
case REQ_ALLOW:
handle_allow(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 1, 0);
break;
case REQ_ALLOWALL:
handle_allowall(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 1, 1);
break;
case REQ_DENY:
handle_deny(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 0, 0);
break;
case REQ_DENYALL:
handle_denyall(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 0, 1);
break;
case REQ_CMDALLOW:
handle_cmdallow(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 1, 0);
break;
case REQ_CMDALLOWALL:
handle_cmdallowall(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 1, 1);
break;
case REQ_CMDDENY:
handle_cmddeny(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 0, 0);
break;
case REQ_CMDDENYALL:
handle_cmddenyall(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 0, 1);
break;
case REQ_ACCHECK:
@@ -2070,6 +1949,14 @@ read_from_cmd_socket(void *anything)
handle_tracking(&rx_message, &tx_message);
break;
case REQ_SMOOTHING:
handle_smoothing(&rx_message, &tx_message);
break;
case REQ_SMOOTHTIME:
handle_smoothtime(&rx_message, &tx_message);
break;
case REQ_SOURCESTATS:
handle_sourcestats(&rx_message, &tx_message);
break;

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2013
* Copyright (C) Miroslav Lichvar 2013-2014
*
* 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
@@ -34,6 +34,7 @@
#include "cmdparse.h"
#include "memory.h"
#include "nameserv.h"
#include "ntp.h"
#include "util.h"
/* ================================================== */
@@ -42,7 +43,7 @@ CPS_Status
CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
{
char *hostname, *cmd;
int ok, n, done;
int n, done;
CPS_Status result;
src->port = SRC_DEFAULT_PORT;
@@ -58,6 +59,10 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
src->params.iburst = 0;
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
src->params.version = NTP_VERSION;
src->params.max_sources = SRC_DEFAULT_MAXSOURCES;
src->params.min_samples = SRC_DEFAULT_MINSAMPLES;
src->params.max_samples = SRC_DEFAULT_MAXSAMPLES;
src->params.sel_option = SRC_SelectNormal;
result = CPS_Success;
@@ -67,10 +72,10 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
if (!*hostname) {
result = CPS_BadHost;
ok = 0;
} else {
src->name = hostname;
/* Parse subfields */
ok = 1;
done = 0;
do {
cmd = line;
@@ -80,7 +85,6 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
if (!strcasecmp(cmd, "port")) {
if (sscanf(line, "%hu%n", &src->port, &n) != 1) {
result = CPS_BadPort;
ok = 0;
done = 1;
} else {
line += n;
@@ -88,7 +92,6 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "minpoll")) {
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1) {
result = CPS_BadMinpoll;
ok = 0;
done = 1;
} else {
line += n;
@@ -96,7 +99,6 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxpoll")) {
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1) {
result = CPS_BadMaxpoll;
ok = 0;
done = 1;
} else {
line += n;
@@ -104,7 +106,6 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "presend")) {
if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1) {
result = CPS_BadPresend;
ok = 0;
done = 1;
} else {
line += n;
@@ -112,7 +113,6 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1) {
result = CPS_BadMaxdelaydevratio;
ok = 0;
done = 1;
} else {
line += n;
@@ -120,7 +120,6 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxdelayratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) {
result = CPS_BadMaxdelayratio;
ok = 0;
done = 1;
} else {
line += n;
@@ -128,16 +127,14 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxdelay")) {
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1) {
result = CPS_BadMaxdelay;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "key")) {
if (sscanf(line, "%lu%n", &src->params.authkey, &n) != 1 ||
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
src->params.authkey == INACTIVE_AUTHKEY) {
result = CPS_BadKey;
ok = 0;
done = 1;
} else {
line += n;
@@ -154,7 +151,6 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "minstratum")) {
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1) {
result = CPS_BadMinstratum;
ok = 0;
done = 1;
} else {
line += n;
@@ -163,7 +159,6 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "polltarget")) {
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1) {
result = CPS_BadPolltarget;
ok = 0;
done = 1;
} else {
line += n;
@@ -175,9 +170,40 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "prefer")) {
src->params.sel_option = SRC_SelectPrefer;
} else if (!strcasecmp(cmd, "version")) {
if (sscanf(line, "%d%n", &src->params.version, &n) != 1) {
result = CPS_BadVersion;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "maxsources")) {
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1) {
result = CPS_BadMaxsources;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "minsamples")) {
if (sscanf(line, "%d%n", &src->params.min_samples, &n) != 1) {
result = CPS_BadMinsamples;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "maxsamples")) {
if (sscanf(line, "%d%n", &src->params.max_samples, &n) != 1) {
result = CPS_BadMaxsamples;
done = 1;
} else {
line += n;
}
} else {
result = CPS_BadOption;
ok = 0;
done = 1;
}
} else {
@@ -186,12 +212,73 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} while (!done);
}
if (ok) {
src->name = strdup(hostname);
return result;
}
/* ================================================== */
void
CPS_StatusToString(CPS_Status status, char *dest, int len)
{
const char *s = NULL;
if (len > 0)
dest[0] = '\0';
switch (status) {
case CPS_Success:
return;
case CPS_BadOption:
s = "server/peer/pool option";
break;
case CPS_BadHost:
s = "address";
break;
case CPS_BadPort:
s = "port";
break;
case CPS_BadMinpoll:
s = "minpoll";
break;
case CPS_BadMaxpoll:
s = "maxpoll";
break;
case CPS_BadPresend:
s = "presend";
break;
case CPS_BadMaxdelaydevratio:
s = "maxdelaydevratio";
break;
case CPS_BadMaxdelayratio:
s = "maxdelayratio";
break;
case CPS_BadMaxdelay:
s = "maxdelay";
break;
case CPS_BadKey:
s = "key";
break;
case CPS_BadMinstratum:
s = "minstratum";
break;
case CPS_BadPolltarget:
s = "polltarget";
break;
case CPS_BadVersion:
s = "version";
break;
case CPS_BadMaxsources:
s = "maxsources";
break;
case CPS_BadMinsamples:
s = "minsamples";
break;
case CPS_BadMaxsamples:
s = "maxsamples";
break;
}
return result;
snprintf(dest, len, "Invalid %s", s);
}
/* ================================================== */
@@ -254,7 +341,7 @@ CPS_SplitWord(char *line)
/* ================================================== */
int
CPS_ParseKey(char *line, unsigned long *id, const char **hash, char **key)
CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key)
{
char *s1, *s2, *s3, *s4;
@@ -267,7 +354,7 @@ CPS_ParseKey(char *line, unsigned long *id, const char **hash, char **key)
if (!*s2 || *s4)
return 0;
if (sscanf(s1, "%lu", id) != 1)
if (sscanf(s1, "%"SCNu32, id) != 1)
return 0;
if (*s3) {

View File

@@ -43,7 +43,11 @@ typedef enum {
CPS_BadMaxdelay,
CPS_BadKey,
CPS_BadMinstratum,
CPS_BadPolltarget
CPS_BadPolltarget,
CPS_BadVersion,
CPS_BadMaxsources,
CPS_BadMinsamples,
CPS_BadMaxsamples,
} CPS_Status;
typedef struct {
@@ -55,6 +59,9 @@ typedef struct {
/* Parse a command to add an NTP server or peer */
extern CPS_Status CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
/* Get a string describing error status */
extern void CPS_StatusToString(CPS_Status status, char *dest, int len);
/* Remove extra white-space and comments */
extern void CPS_NormalizeLine(char *line);
@@ -62,6 +69,6 @@ extern void CPS_NormalizeLine(char *line);
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);
extern int CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key);
#endif /* GOT_CMDPARSE_H */

504
conf.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* 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,6 +29,7 @@
#include "sysincl.h"
#include "array.h"
#include "conf.h"
#include "ntp_sources.h"
#include "ntp_core.h"
@@ -39,7 +40,6 @@
#include "nameserv.h"
#include "memory.h"
#include "cmdparse.h"
#include "broadcast.h"
#include "util.h"
/* ================================================== */
@@ -47,7 +47,7 @@
static int parse_string(char *line, char **result);
static int parse_int(char *line, int *result);
static int parse_unsignedlong(char *, unsigned long *result);
static int parse_uint32(char *, uint32_t *result);
static int parse_double(char *line, double *result);
static int parse_null(char *line);
@@ -63,14 +63,17 @@ static void parse_deny(char *);
static void parse_fallbackdrift(char *);
static void parse_include(char *);
static void parse_initstepslew(char *);
static void parse_leapsecmode(char *);
static void parse_local(char *);
static void parse_log(char *);
static void parse_mailonchange(char *);
static void parse_makestep(char *);
static void parse_maxchange(char *);
static void parse_peer(char *);
static void parse_pool(char *);
static void parse_refclock(char *);
static void parse_server(char *);
static void parse_smoothtime(char *);
static void parse_tempcomp(char *);
/* ================================================== */
@@ -78,20 +81,20 @@ static void parse_tempcomp(char *);
static int restarted = 0;
static int generate_command_key = 0;
static char *rtc_device = "/dev/rtc";
static char *rtc_device;
static int acquisition_port = -1;
static int ntp_port = 123;
static char *keys_file = NULL;
static char *drift_file = NULL;
static char *rtc_file = NULL;
static unsigned long command_key_id;
static uint32_t command_key_id;
static double max_update_skew = 1000.0;
static double correction_time_ratio = 3.0;
static double max_clock_error = 1.0; /* in ppm */
static double max_slew_rate = 1e6 / 12.0; /* in ppm */
static double reselect_distance = 1e-4;
static double stratum_weight = 1.0;
static double stratum_weight = 1e-3;
static double combine_limit = 3.0;
static int cmd_port = DEFAULT_CANDM_PORT;
@@ -104,19 +107,17 @@ static int do_log_refclocks = 0;
static int do_log_tempcomp = 0;
static int do_dump_on_exit = 0;
static int log_banner = 32;
static char *logdir = ".";
static char *dumpdir = ".";
static char *logdir;
static char *dumpdir;
static int enable_local=0;
static int local_stratum;
static int n_init_srcs;
/* Threshold (in seconds) - if absolute value of initial error is less
than this, slew instead of stepping */
static double init_slew_threshold;
#define MAX_INIT_SRCS 8
static IPAddr init_srcs_ip[MAX_INIT_SRCS];
/* Array of IPAddr */
static ARR_Instance init_sources;
static int enable_manual=0;
@@ -137,6 +138,9 @@ static double make_step_threshold = 0.0;
/* Threshold for automatic RTC trimming */
static double rtc_autotrim_threshold = 0.0;
/* Minimum number of selectables sources required to update the clock */
static int min_sources = 1;
/* Number of updates before offset checking, number of ignored updates
before exiting and the maximum allowed offset */
static int max_offset_delay = -1;
@@ -175,64 +179,67 @@ static IPAddr bind_address4, bind_address6;
static IPAddr bind_acq_address4, bind_acq_address6;
/* IP addresses for binding the command socket to. UNSPEC family means
use the value of bind_address */
the loopback address will be used */
static IPAddr bind_cmd_address4, bind_cmd_address6;
/* Filename to use for storing pid of running chronyd, to prevent multiple
* chronyds being started. */
static char *pidfile = "/var/run/chronyd.pid";
static char *pidfile;
/* Smoothing constants */
static double smooth_max_freq = 0.0; /* in ppm */
static double smooth_max_wander = 0.0; /* in ppm/s */
static int smooth_leap_only = 0;
/* Temperature sensor, update interval and compensation coefficients */
static char *tempcomp_file = NULL;
static char *tempcomp_sensor_file = NULL;
static char *tempcomp_point_file = NULL;
static double tempcomp_interval;
static double tempcomp_T0, tempcomp_k0, tempcomp_k1, tempcomp_k2;
static int sched_priority = 0;
static int lock_memory = 0;
/* Leap second handling mode */
static REF_LeapMode leapsec_mode = REF_LeapModeSystem;
/* Name of a system timezone containing leap seconds occuring at midnight */
static char *leapsec_tz = NULL;
/* Name of the user to which will be dropped root privileges. */
static char *user = DEFAULT_USER;
static char *user;
typedef struct {
NTP_Source_Type type;
int pool;
CPS_NTP_Source params;
} NTP_Source;
#define MAX_NTP_SOURCES 64
/* Array of NTP_Source */
static ARR_Instance ntp_sources;
static NTP_Source ntp_sources[MAX_NTP_SOURCES];
static int n_ntp_sources = 0;
#define MAX_RCL_SOURCES 8
static RefclockParameters refclock_sources[MAX_RCL_SOURCES];
static int n_refclock_sources = 0;
/* Array of RefclockParameters */
static ARR_Instance refclock_sources;
typedef struct _AllowDeny {
struct _AllowDeny *next;
struct _AllowDeny *prev;
IPAddr ip;
int subnet_bits;
int all; /* 1 to override existing more specific defns */
int allow; /* 0 for deny, 1 for allow */
} AllowDeny;
static AllowDeny ntp_auth_list = {&ntp_auth_list, &ntp_auth_list};
static AllowDeny cmd_auth_list = {&cmd_auth_list, &cmd_auth_list};
/* Arrays of AllowDeny */
static ARR_Instance ntp_restrictions;
static ARR_Instance cmd_restrictions;
typedef struct {
/* Both in host (not necessarily network) order */
IPAddr addr;
unsigned short port;
int interval;
} NTP_Broadcast_Destination;
static NTP_Broadcast_Destination *broadcasts = NULL;
static int max_broadcasts = 0;
static int n_broadcasts = 0;
/* Array of NTP_Broadcast_Destination */
static ARR_Instance broadcasts;
/* ================================================== */
@@ -263,18 +270,31 @@ other_parse_error(const char *message)
/* ================================================== */
static void
check_number_of_args(char *line, int num)
static int
get_number_of_args(char *line)
{
int num = 0;
/* The line is normalized, between arguments is just one space */
if (*line == ' ')
line++;
if (*line)
num--;
num++;
for (; *line; line++) {
if (*line == ' ')
num--;
num++;
}
return num;
}
/* ================================================== */
static void
check_number_of_args(char *line, int num)
{
num -= get_number_of_args(line);
if (num) {
LOG_FATAL(LOGF_Configure, "%s arguments for %s directive at line %d%s%s",
num > 0 ? "Missing" : "Too many",
@@ -286,9 +306,56 @@ check_number_of_args(char *line, int num)
/* ================================================== */
void
CNF_SetRestarted(int r)
CNF_Initialise(int r)
{
restarted = r;
init_sources = ARR_CreateInstance(sizeof (IPAddr));
ntp_sources = ARR_CreateInstance(sizeof (NTP_Source));
refclock_sources = ARR_CreateInstance(sizeof (RefclockParameters));
broadcasts = ARR_CreateInstance(sizeof (NTP_Broadcast_Destination));
ntp_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
cmd_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
dumpdir = Strdup(".");
logdir = Strdup(".");
pidfile = Strdup("/var/run/chronyd.pid");
rtc_device = Strdup("/dev/rtc");
user = Strdup(DEFAULT_USER);
}
/* ================================================== */
void
CNF_Finalise(void)
{
unsigned int i;
for (i = 0; i < ARR_GetSize(ntp_sources); i++)
Free(((NTP_Source *)ARR_GetElement(ntp_sources, i))->params.name);
ARR_DestroyInstance(init_sources);
ARR_DestroyInstance(ntp_sources);
ARR_DestroyInstance(refclock_sources);
ARR_DestroyInstance(broadcasts);
ARR_DestroyInstance(ntp_restrictions);
ARR_DestroyInstance(cmd_restrictions);
Free(drift_file);
Free(dumpdir);
Free(hwclock_file);
Free(keys_file);
Free(leapsec_tz);
Free(logdir);
Free(pidfile);
Free(rtc_device);
Free(rtc_file);
Free(user);
Free(mail_user_on_change);
Free(tempcomp_sensor_file);
Free(tempcomp_point_file);
}
/* ================================================== */
@@ -360,7 +427,7 @@ CNF_ParseLine(const char *filename, int number, char *line)
} else if (!strcasecmp(command, "combinelimit")) {
parse_double(p, &combine_limit);
} else if (!strcasecmp(command, "commandkey")) {
parse_unsignedlong(p, &command_key_id);
parse_uint32(p, &command_key_id);
} else if (!strcasecmp(command, "corrtimeratio")) {
parse_double(p, &correction_time_ratio);
} else if (!strcasecmp(command, "deny")) {
@@ -383,6 +450,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
parse_initstepslew(p);
} else if (!strcasecmp(command, "keyfile")) {
parse_string(p, &keys_file);
} else if (!strcasecmp(command, "leapsecmode")) {
parse_leapsecmode(p);
} else if (!strcasecmp(command, "leapsectz")) {
parse_string(p, &leapsec_tz);
} else if (!strcasecmp(command, "linux_freq_scale")) {
@@ -419,12 +488,16 @@ CNF_ParseLine(const char *filename, int number, char *line)
parse_double(p, &max_update_skew);
} else if (!strcasecmp(command, "minsamples")) {
parse_int(p, &min_samples);
} else if (!strcasecmp(command, "minsources")) {
parse_int(p, &min_sources);
} else if (!strcasecmp(command, "noclientlog")) {
no_client_log = parse_null(p);
} else if (!strcasecmp(command, "peer")) {
parse_peer(p);
} else if (!strcasecmp(command, "pidfile")) {
parse_string(p, &pidfile);
} else if (!strcasecmp(command, "pool")) {
parse_pool(p);
} else if (!strcasecmp(command, "port")) {
parse_int(p, &ntp_port);
} else if (!strcasecmp(command, "refclock")) {
@@ -445,6 +518,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
parse_int(p, &sched_priority);
} else if (!strcasecmp(command, "server")) {
parse_server(p);
} else if (!strcasecmp(command, "smoothtime")) {
parse_smoothtime(p);
} else if (!strcasecmp(command, "stratumweight")) {
parse_double(p, &stratum_weight);
} else if (!strcasecmp(command, "tempcomp")) {
@@ -462,7 +537,8 @@ static int
parse_string(char *line, char **result)
{
check_number_of_args(line, 1);
*result = strdup(line);
Free(*result);
*result = Strdup(line);
return 1;
}
@@ -482,10 +558,10 @@ parse_int(char *line, int *result)
/* ================================================== */
static int
parse_unsignedlong(char *line, unsigned long *result)
parse_uint32(char *line, uint32_t *result)
{
check_number_of_args(line, 1);
if (sscanf(line, "%lu", result) != 1) {
if (sscanf(line, "%"SCNu32, result) != 1) {
command_parse_error();
return 0;
}
@@ -517,57 +593,24 @@ parse_null(char *line)
/* ================================================== */
static void
parse_source(char *line, NTP_Source_Type type)
parse_source(char *line, NTP_Source_Type type, int pool)
{
CPS_Status status;
NTP_Source source;
char str[64];
if (n_ntp_sources >= MAX_NTP_SOURCES)
source.type = type;
source.pool = pool;
status = CPS_ParseNTPSourceAdd(line, &source.params);
if (status != CPS_Success) {
CPS_StatusToString(status, str, sizeof (str));
other_parse_error(str);
return;
ntp_sources[n_ntp_sources].type = type;
status = CPS_ParseNTPSourceAdd(line, &ntp_sources[n_ntp_sources].params);
switch (status) {
case CPS_Success:
n_ntp_sources++;
break;
case CPS_BadOption:
other_parse_error("Invalid server/peer parameter");
break;
case CPS_BadHost:
other_parse_error("Invalid host/IP address");
break;
case CPS_BadPort:
other_parse_error("Unreadable port");
break;
case CPS_BadMinpoll:
other_parse_error("Unreadable minpoll");
break;
case CPS_BadMaxpoll:
other_parse_error("Unreadable maxpoll");
break;
case CPS_BadPresend:
other_parse_error("Unreadable presend");
break;
case CPS_BadMaxdelaydevratio:
other_parse_error("Unreadable maxdelaydevratio");
break;
case CPS_BadMaxdelayratio:
other_parse_error("Unreadable maxdelayratio");
break;
case CPS_BadMaxdelay:
other_parse_error("Unreadable maxdelay");
break;
case CPS_BadKey:
other_parse_error("Unreadable key");
break;
case CPS_BadMinstratum:
other_parse_error("Unreadable minstratum");
break;
case CPS_BadPolltarget:
other_parse_error("Unreadable polltarget");
break;
}
source.params.name = Strdup(source.params.name);
ARR_AppendElement(ntp_sources, &source);
}
/* ================================================== */
@@ -575,7 +618,7 @@ parse_source(char *line, NTP_Source_Type type)
static void
parse_server(char *line)
{
parse_source(line, NTP_SERVER);
parse_source(line, NTP_SERVER, 0);
}
/* ================================================== */
@@ -583,7 +626,15 @@ parse_server(char *line)
static void
parse_peer(char *line)
{
parse_source(line, NTP_PEER);
parse_source(line, NTP_PEER, 0);
}
/* ================================================== */
static void
parse_pool(char *line)
{
parse_source(line, NTP_SERVER, 1);
}
/* ================================================== */
@@ -591,21 +642,20 @@ parse_peer(char *line)
static void
parse_refclock(char *line)
{
int i, n, poll, dpoll, filter_length, pps_rate;
int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples;
uint32_t ref_id, lock_ref_id;
double offset, delay, precision, max_dispersion;
char *p, *cmd, *name, *param;
unsigned char ref[5];
SRC_SelectOption sel_option;
i = n_refclock_sources;
if (i >= MAX_RCL_SOURCES)
return;
RefclockParameters *refclock;
poll = 4;
dpoll = 0;
filter_length = 64;
pps_rate = 0;
min_samples = SRC_DEFAULT_MINSAMPLES;
max_samples = SRC_DEFAULT_MAXSAMPLES;
offset = 0.0;
delay = 1e-9;
precision = 0.0;
@@ -627,11 +677,11 @@ parse_refclock(char *line)
return;
}
name = strdup(p);
name = Strdup(p);
p = line;
line = CPS_SplitWord(line);
param = strdup(p);
param = Strdup(p);
while (*line) {
cmd = line;
@@ -659,6 +709,12 @@ parse_refclock(char *line)
} else if (!strcasecmp(cmd, "rate")) {
if (sscanf(line, "%d%n", &pps_rate, &n) != 1)
break;
} else if (!strcasecmp(cmd, "minsamples")) {
if (sscanf(line, "%d%n", &min_samples, &n) != 1)
break;
} else if (!strcasecmp(cmd, "maxsamples")) {
if (sscanf(line, "%d%n", &max_samples, &n) != 1)
break;
} else if (!strcasecmp(cmd, "offset")) {
if (sscanf(line, "%lf%n", &offset, &n) != 1)
break;
@@ -688,21 +744,22 @@ parse_refclock(char *line)
return;
}
refclock_sources[i].driver_name = name;
refclock_sources[i].driver_parameter = param;
refclock_sources[i].driver_poll = dpoll;
refclock_sources[i].poll = poll;
refclock_sources[i].filter_length = filter_length;
refclock_sources[i].pps_rate = pps_rate;
refclock_sources[i].offset = offset;
refclock_sources[i].delay = delay;
refclock_sources[i].precision = precision;
refclock_sources[i].max_dispersion = max_dispersion;
refclock_sources[i].sel_option = sel_option;
refclock_sources[i].ref_id = ref_id;
refclock_sources[i].lock_ref_id = lock_ref_id;
n_refclock_sources++;
refclock = (RefclockParameters *)ARR_GetNewElement(refclock_sources);
refclock->driver_name = name;
refclock->driver_parameter = param;
refclock->driver_poll = dpoll;
refclock->poll = poll;
refclock->filter_length = filter_length;
refclock->pps_rate = pps_rate;
refclock->min_samples = min_samples;
refclock->max_samples = max_samples;
refclock->offset = offset;
refclock->delay = delay;
refclock->precision = precision;
refclock->max_dispersion = max_dispersion;
refclock->sel_option = sel_option;
refclock->ref_id = ref_id;
refclock->lock_ref_id = lock_ref_id;
}
/* ================================================== */
@@ -764,7 +821,7 @@ parse_initstepslew(char *line)
return;
}
n_init_srcs = 0;
ARR_SetSize(init_sources, 0);
p = CPS_SplitWord(line);
if (sscanf(line, "%lf", &init_slew_threshold) != 1) {
@@ -776,22 +833,34 @@ parse_initstepslew(char *line)
hostname = p;
p = CPS_SplitWord(p);
if (*hostname) {
if (DNS_Name2IPAddress(hostname, &ip_addr) == DNS_Success) {
init_srcs_ip[n_init_srcs] = ip_addr;
++n_init_srcs;
if (DNS_Name2IPAddress(hostname, &ip_addr, 1) == DNS_Success) {
ARR_AppendElement(init_sources, &ip_addr);
} else {
LOG(LOGS_WARN, LOGF_Configure, "Could not resolve address of initstepslew server %s", hostname);
}
if (n_init_srcs >= MAX_INIT_SRCS) {
other_parse_error("Too many initstepslew servers");
}
}
}
}
/* ================================================== */
static void
parse_leapsecmode(char *line)
{
if (!strcasecmp(line, "system"))
leapsec_mode = REF_LeapModeSystem;
else if (!strcasecmp(line, "slew"))
leapsec_mode = REF_LeapModeSlew;
else if (!strcasecmp(line, "step"))
leapsec_mode = REF_LeapModeStep;
else if (!strcasecmp(line, "ignore"))
leapsec_mode = REF_LeapModeIgnore;
else
command_parse_error();
}
/* ================================================== */
static void
parse_clientloglimit(char *line)
{
@@ -855,8 +924,9 @@ parse_mailonchange(char *line)
check_number_of_args(line, 2);
address = line;
line = CPS_SplitWord(line);
Free(mail_user_on_change);
if (sscanf(line, "%lf", &mail_change_threshold) == 1) {
mail_user_on_change = strdup(address);
mail_user_on_change = Strdup(address);
} else {
mail_user_on_change = NULL;
command_parse_error();
@@ -866,7 +936,7 @@ parse_mailonchange(char *line)
/* ================================================== */
static void
parse_allow_deny(char *line, AllowDeny *list, int allow)
parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
{
char *p;
unsigned long a, b, c, d, n;
@@ -883,7 +953,7 @@ parse_allow_deny(char *line, AllowDeny *list, int allow)
if (!*p) {
/* Empty line applies to all addresses */
new_node = MallocNew(AllowDeny);
new_node = (AllowDeny *)ARR_GetNewElement(restrictions);
new_node->allow = allow;
new_node->all = all;
new_node->ip.family = IPADDR_UNSPEC;
@@ -897,7 +967,7 @@ parse_allow_deny(char *line, AllowDeny *list, int allow)
n = 0;
if (UTI_StringToIP(p, &ip_addr) ||
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) >= 1) {
new_node = MallocNew(AllowDeny);
new_node = (AllowDeny *)ARR_GetNewElement(restrictions);
new_node->allow = allow;
new_node->all = all;
@@ -948,8 +1018,8 @@ parse_allow_deny(char *line, AllowDeny *list, int allow)
}
} else {
if (DNS_Name2IPAddress(p, &ip_addr) == DNS_Success) {
new_node = MallocNew(AllowDeny);
if (DNS_Name2IPAddress(p, &ip_addr, 1) == DNS_Success) {
new_node = (AllowDeny *)ARR_GetNewElement(restrictions);
new_node->allow = allow;
new_node->all = all;
new_node->ip = ip_addr;
@@ -962,14 +1032,6 @@ parse_allow_deny(char *line, AllowDeny *list, int allow)
}
}
}
if (new_node) {
new_node->prev = list->prev;
new_node->next = list;
list->prev->next = new_node;
list->prev = new_node;
}
}
@@ -978,7 +1040,7 @@ parse_allow_deny(char *line, AllowDeny *list, int allow)
static void
parse_allow(char *line)
{
parse_allow_deny(line, &ntp_auth_list, 1);
parse_allow_deny(line, ntp_restrictions, 1);
}
@@ -987,7 +1049,7 @@ parse_allow(char *line)
static void
parse_deny(char *line)
{
parse_allow_deny(line, &ntp_auth_list, 0);
parse_allow_deny(line, ntp_restrictions, 0);
}
/* ================================================== */
@@ -995,7 +1057,7 @@ parse_deny(char *line)
static void
parse_cmdallow(char *line)
{
parse_allow_deny(line, &cmd_auth_list, 1);
parse_allow_deny(line, cmd_restrictions, 1);
}
@@ -1004,7 +1066,7 @@ parse_cmdallow(char *line)
static void
parse_cmddeny(char *line)
{
parse_allow_deny(line, &cmd_auth_list, 0);
parse_allow_deny(line, cmd_restrictions, 0);
}
/* ================================================== */
@@ -1067,6 +1129,7 @@ static void
parse_broadcast(char *line)
{
/* Syntax : broadcast <interval> <broadcast-IP-addr> [<port>] */
NTP_Broadcast_Destination *destination;
int port;
int interval;
char *p;
@@ -1101,30 +1164,48 @@ parse_broadcast(char *line)
port = 123;
}
if (max_broadcasts == n_broadcasts) {
/* Expand array */
max_broadcasts += 8;
if (broadcasts) {
broadcasts = ReallocArray(NTP_Broadcast_Destination, max_broadcasts, broadcasts);
} else {
broadcasts = MallocArray(NTP_Broadcast_Destination, max_broadcasts);
}
}
broadcasts[n_broadcasts].addr = ip;
broadcasts[n_broadcasts].port = port;
broadcasts[n_broadcasts].interval = interval;
++n_broadcasts;
destination = (NTP_Broadcast_Destination *)ARR_GetNewElement(broadcasts);
destination->addr = ip;
destination->port = port;
destination->interval = interval;
}
/* ================================================== */
static void
parse_smoothtime(char *line)
{
if (get_number_of_args(line) != 3)
check_number_of_args(line, 2);
if (sscanf(line, "%lf %lf", &smooth_max_freq, &smooth_max_wander) != 2) {
smooth_max_freq = 0.0;
command_parse_error();
}
line = CPS_SplitWord(CPS_SplitWord(line));
smooth_leap_only = 0;
if (*line) {
if (!strcasecmp(line, "leaponly"))
smooth_leap_only = 1;
else
command_parse_error();
}
}
/* ================================================== */
static void
parse_tempcomp(char *line)
{
char *p;
int point_form;
point_form = get_number_of_args(line) == 3;
if (!point_form)
check_number_of_args(line, 6);
check_number_of_args(line, 6);
p = line;
line = CPS_SplitWord(line);
@@ -1133,12 +1214,25 @@ parse_tempcomp(char *line)
return;
}
if (sscanf(line, "%lf %lf %lf %lf %lf", &tempcomp_interval, &tempcomp_T0, &tempcomp_k0, &tempcomp_k1, &tempcomp_k2) != 5) {
command_parse_error();
return;
Free(tempcomp_point_file);
if (point_form) {
if (sscanf(line, "%lf", &tempcomp_interval) != 1) {
command_parse_error();
return;
}
tempcomp_point_file = Strdup(CPS_SplitWord(line));
} else {
if (sscanf(line, "%lf %lf %lf %lf %lf", &tempcomp_interval,
&tempcomp_T0, &tempcomp_k0, &tempcomp_k1, &tempcomp_k2) != 5) {
command_parse_error();
return;
}
tempcomp_point_file = NULL;
}
tempcomp_file = strdup(p);
Free(tempcomp_sensor_file);
tempcomp_sensor_file = Strdup(p);
}
/* ================================================== */
@@ -1158,43 +1252,54 @@ CNF_AddInitSources(void)
CPS_NTP_Source cps_source;
NTP_Remote_Address ntp_addr;
char dummy_hostname[2] = "H";
int i;
unsigned int i;
for (i = 0; i < n_init_srcs; i++) {
for (i = 0; i < ARR_GetSize(init_sources); i++) {
/* Get the default NTP params */
CPS_ParseNTPSourceAdd(dummy_hostname, &cps_source);
/* Add the address as an offline iburst server */
ntp_addr.ip_addr = init_srcs_ip[i];
ntp_addr.ip_addr = *(IPAddr *)ARR_GetElement(init_sources, i);
ntp_addr.port = cps_source.port;
cps_source.params.iburst = 1;
cps_source.params.online = 0;
NSR_AddSource(&ntp_addr, NTP_SERVER, &cps_source.params);
}
ARR_SetSize(init_sources, 0);
}
/* ================================================== */
void
CNF_AddSources(void) {
int i;
CNF_AddSources(void)
{
NTP_Source *source;
unsigned int i;
for (i=0; i<n_ntp_sources; i++) {
NSR_AddUnresolvedSource(ntp_sources[i].params.name, ntp_sources[i].params.port,
ntp_sources[i].type, &ntp_sources[i].params.params);
for (i = 0; i < ARR_GetSize(ntp_sources); i++) {
source = (NTP_Source *)ARR_GetElement(ntp_sources, i);
NSR_AddSourceByName(source->params.name, source->params.port,
source->pool, source->type, &source->params.params);
Free(source->params.name);
}
ARR_SetSize(ntp_sources, 0);
}
/* ================================================== */
void
CNF_AddRefclocks(void) {
int i;
CNF_AddRefclocks(void)
{
unsigned int i;
for (i=0; i<n_refclock_sources; i++) {
RCL_AddRefclock(&refclock_sources[i]);
for (i = 0; i < ARR_GetSize(refclock_sources); i++) {
RCL_AddRefclock((RefclockParameters *)ARR_GetElement(refclock_sources, i));
}
ARR_SetSize(refclock_sources, 0);
}
/* ================================================== */
@@ -1202,12 +1307,16 @@ CNF_AddRefclocks(void) {
void
CNF_AddBroadcasts(void)
{
int i;
for (i=0; i<n_broadcasts; i++) {
BRD_AddDestination(&broadcasts[i].addr,
broadcasts[i].port,
broadcasts[i].interval);
unsigned int i;
NTP_Broadcast_Destination *destination;
for (i = 0; i < ARR_GetSize(broadcasts); i++) {
destination = (NTP_Broadcast_Destination *)ARR_GetElement(broadcasts, i);
NCR_AddBroadcastDestination(&destination->addr, destination->port,
destination->interval);
}
ARR_SetSize(broadcasts, 0);
}
/* ================================================== */
@@ -1340,7 +1449,7 @@ CNF_GetRtcDevice(void)
/* ================================================== */
unsigned long
uint32_t
CNF_GetCommandKey(void)
{
return command_key_id;
@@ -1513,20 +1622,26 @@ CNF_SetupAccessRestrictions(void)
{
AllowDeny *node;
int status;
unsigned int i;
for (node = ntp_auth_list.next; node != &ntp_auth_list; node = node->next) {
for (i = 0; i < ARR_GetSize(ntp_restrictions); i++) {
node = ARR_GetElement(ntp_restrictions, i);
status = NCR_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all);
if (!status) {
LOG_FATAL(LOGF_Configure, "Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
}
}
for (node = cmd_auth_list.next; node != &cmd_auth_list; node = node->next) {
for (i = 0; i < ARR_GetSize(cmd_restrictions); i++) {
node = ARR_GetElement(cmd_restrictions, i);
status = CAM_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all);
if (!status) {
LOG_FATAL(LOGF_Configure, "Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
}
}
ARR_SetSize(ntp_restrictions, 0);
ARR_SetSize(cmd_restrictions, 0);
}
/* ================================================== */
@@ -1586,9 +1701,9 @@ void
CNF_GetBindCommandAddress(int family, IPAddr *addr)
{
if (family == IPADDR_INET4)
*addr = bind_cmd_address4.family != IPADDR_UNSPEC ? bind_cmd_address4 : bind_address4;
*addr = bind_cmd_address4;
else if (family == IPADDR_INET6)
*addr = bind_cmd_address6.family != IPADDR_UNSPEC ? bind_cmd_address6 : bind_address6;
*addr = bind_cmd_address6;
else
addr->family = IPADDR_UNSPEC;
}
@@ -1603,6 +1718,14 @@ CNF_GetPidFile(void)
/* ================================================== */
REF_LeapMode
CNF_GetLeapSecMode(void)
{
return leapsec_mode;
}
/* ================================================== */
char *
CNF_GetLeapSecTimezone(void)
{
@@ -1628,9 +1751,20 @@ CNF_GetLockMemory(void)
/* ================================================== */
void
CNF_GetTempComp(char **file, double *interval, double *T0, double *k0, double *k1, double *k2)
CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only)
{
*file = tempcomp_file;
*max_freq = smooth_max_freq;
*max_wander = smooth_max_wander;
*leap_only = smooth_leap_only;
}
/* ================================================== */
void
CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2)
{
*file = tempcomp_sensor_file;
*point_file = tempcomp_point_file;
*interval = tempcomp_interval;
*T0 = tempcomp_T0;
*k0 = tempcomp_k0;
@@ -1664,6 +1798,14 @@ CNF_GetMinSamples(void)
/* ================================================== */
int
CNF_GetMinSources(void)
{
return min_sources;
}
/* ================================================== */
char *
CNF_GetHwclockFile(void)
{
@@ -1675,7 +1817,7 @@ CNF_GetHwclockFile(void)
int
CNF_GetInitSources(void)
{
return n_init_srcs;
return ARR_GetSize(init_sources);
}
/* ================================================== */

12
conf.h
View File

@@ -29,8 +29,10 @@
#define GOT_CONF_H
#include "addressing.h"
#include "reference.h"
extern void CNF_SetRestarted(int);
extern void CNF_Initialise(int restarted);
extern void CNF_Finalise(void);
extern char *CNF_GetRtcDevice(void);
@@ -56,7 +58,7 @@ extern int CNF_GetLogRefclocks(void);
extern int CNF_GetLogTempComp(void);
extern char *CNF_GetKeysFile(void);
extern char *CNF_GetRtcFile(void);
extern unsigned long CNF_GetCommandKey(void);
extern uint32_t CNF_GetCommandKey(void);
extern int CNF_GetGenerateCommandKey(void);
extern int CNF_GetDumpOnExit(void);
extern int CNF_GetManualEnabled(void);
@@ -74,6 +76,7 @@ extern void CNF_GetBindAddress(int family, IPAddr *addr);
extern void CNF_GetBindAcquisitionAddress(int family, IPAddr *addr);
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
extern char *CNF_GetPidFile(void);
extern REF_LeapMode CNF_GetLeapSecMode(void);
extern char *CNF_GetLeapSecTimezone(void);
/* Value returned in ppm, as read from file */
@@ -93,13 +96,16 @@ extern void CNF_SetupAccessRestrictions(void);
extern int CNF_GetSchedPriority(void);
extern int CNF_GetLockMemory(void);
extern void CNF_GetTempComp(char **file, double *interval, double *T0, double *k0, double *k1, double *k2);
extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only);
extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
extern char *CNF_GetUser(void);
extern int CNF_GetMaxSamples(void);
extern int CNF_GetMinSamples(void);
extern int CNF_GetMinSources(void);
extern double CNF_GetRtcAutotrim(void);
extern char *CNF_GetHwclockFile(void);

128
configure vendored
View File

@@ -8,8 +8,6 @@
#
# =======================================================================
rm -f config.h config.log
# This configure script determines the operating system type and version
if [ "x${CC}" = "x" ]; then
@@ -105,13 +103,17 @@ 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
--disable-sechash Disable support for hashes other than MD5
--without-nss Don't use NSS even if it is available
--without-tomcrypt Don't use libtomcrypt even if it is available
--disable-cmdmon Disable command and monitoring support
--disable-ntp Disable NTP support
--disable-refclock Disable reference clock support
--disable-phc Disable PHC refclock driver
--disable-pps Disable PPS refclock driver
--disable-ipv6 Disable IPv6 support
--disable-phc Disable PHC support
--disable-pps Disable PPS API support
--disable-rtc Don't include RTC even on Linux
--disable-linuxcaps Disable Linux capabilities support
--disable-linuxcaps Disable libcap (Linux capabilities) support
--disable-asyncdns Disable asynchronous name resolving
--disable-forcednsretry Don't retry on permanent DNS error
--with-ntp-era=SECONDS Specify earliest assumed NTP time in seconds
@@ -167,6 +169,22 @@ pkg_config () {
pkg-config $@ 2> /dev/null
}
#}}}
#{{{ get_features
get_features () {
ff=1
for f; do
if [ "$ff" = "0" ]; then
echo -n " "
fi
if grep "define FEAT_$f" config.h > /dev/null; then
echo -n "+$f"
else
echo -n "-$f"
fi
ff=0
done
}
#}}}
# ======================================================================
@@ -182,16 +200,20 @@ EXTRA_OBJECTS=""
EXTRA_DEFS=""
SYSDEFS=""
debug=0
feat_debug=0
feat_cmdmon=1
feat_ntp=1
feat_refclock=1
feat_readline=1
try_readline=1
try_editline=1
feat_sechash=1
try_nss=1
try_tomcrypt=1
feat_rtc=1
try_rtc=0
feat_linuxcaps=1
try_linuxcaps=0
feat_droproot=1
try_libcap=0
readline_lib=""
readline_inc=""
ncurses_lib=""
@@ -211,7 +233,7 @@ for option
do
case "$option" in
--enable-debug )
debug=1
feat_debug=1
;;
--disable-readline )
feat_readline=0
@@ -264,6 +286,15 @@ do
--chronyvardir=* )
SETCHRONYVARDIR=`echo $option | sed -e 's/^.*=//;'`
;;
--disable-cmdmon)
feat_cmdmon=0
;;
--disable-ntp)
feat_ntp=0
;;
--disable-refclock)
feat_refclock=0
;;
--disable-rtc)
feat_rtc=0
;;
@@ -277,7 +308,7 @@ do
feat_pps=0
;;
--disable-linuxcaps)
feat_linuxcaps=0
feat_droproot=0
;;
--disable-asyncdns)
feat_asyncdns=0
@@ -294,6 +325,9 @@ do
--with-sendmail=* )
mail_program=`echo $option | sed -e 's/^.*=//;'`
;;
--disable-sechash )
feat_sechash=0
;;
--without-nss )
try_nss=0
;;
@@ -318,6 +352,8 @@ do
esac
done
rm -f config.h config.log
SYSTEM=${OPERATINGSYSTEM}-${MACHINE}
case $SYSTEM in
@@ -340,7 +376,7 @@ case $SYSTEM in
;;
Linux* )
EXTRA_OBJECTS="sys_generic.o sys_linux.o wrap_adjtimex.o"
try_linuxcaps=1
try_libcap=1
try_rtc=1
try_setsched=1
try_lockmem=1
@@ -368,6 +404,13 @@ case $SYSTEM in
SYSDEFS=""
echo "Configuring for $SYSTEM"
;;
Darwin-* )
EXTRA_OBJECTS="sys_macosx.o"
EXTRA_LIBS="-lresolv"
EXTRA_CLI_LIBS="-lresolv"
add_def MACOSX
echo "Configuring for MacOS X (" $SYSTEM "MacOS X version" $VERSION ")"
;;
SunOS-i86pc* )
# Doug Woodward <dougw@whistler.com> reported that this configuration
# works for Solaris 2.8 / SunOS 5.8 on x86 platforms
@@ -389,6 +432,34 @@ case $SYSTEM in
;;
esac
if [ $feat_debug = "1" ]; then
add_def FEAT_DEBUG
fi
add_def DEBUG $feat_debug
if [ $feat_cmdmon = "1" ]; then
add_def FEAT_CMDMON
EXTRA_OBJECTS="$EXTRA_OBJECTS cmdmon.o manual.o pktlength.o"
fi
if [ $feat_ntp = "1" ]; then
add_def FEAT_NTP
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_core.o ntp_io.o ntp_sources.o"
else
feat_asyncdns=0
fi
if [ "$feat_cmdmon" = "1" ] || [ $feat_ntp = "1" ]; then
EXTRA_OBJECTS="$EXTRA_OBJECTS addrfilt.o clientlog.o keys.o nameserv.o"
else
feat_ipv6=0
fi
if [ $feat_refclock = "1" ]; then
add_def FEAT_REFCLOCK
EXTRA_OBJECTS="$EXTRA_OBJECTS refclock.o refclock_phc.o refclock_pps.o refclock_shm.o refclock_sock.o"
fi
if test_code '64-bit time_t' 'time.h' '' '' '
char x[sizeof(time_t) > 4 ? 1 : -1] = {0};
return x[0];'
@@ -436,11 +507,11 @@ else
fi
if test_code '<stdint.h>' 'stdint.h' '' '' ''; then
add_def HAS_STDINT_H
add_def HAVE_STDINT_H
fi
if test_code '<inttypes.h>' 'inttypes.h' '' '' ''; then
add_def HAS_INTTYPES_H
add_def HAVE_INTTYPES_H
fi
if [ $feat_ipv6 = "1" ] && \
@@ -450,7 +521,7 @@ if [ $feat_ipv6 = "1" ] && \
n.sin6_addr = in6addr_any;
return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));'
then
add_def HAVE_IPV6
add_def FEAT_IPV6
if test_code 'in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
return sizeof(struct in6_pktinfo);'
then
@@ -477,11 +548,12 @@ if [ $feat_asyncdns = "1" ] && \
then
add_def FEAT_ASYNCDNS
add_def USE_PTHREAD_ASYNCDNS
EXTRA_OBJECTS="$EXTRA_OBJECTS nameserv_async.o"
MYCFLAGS="$MYCFLAGS -pthread"
fi
timepps_h=""
if [ $feat_pps = "1" ]; then
if [ $feat_refclock = "1" ] && [ $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
@@ -500,17 +572,17 @@ if [ "x$timepps_h" != "x" ] && \
struct timespec ts;
return time_pps_fetch(h, PPS_TSFMT_TSPEC, &i, &ts);'
then
add_def HAVE_PPSAPI
add_def FEAT_PPS
fi
if [ $feat_linuxcaps = "1" ] && [ $try_linuxcaps = "1" ] && \
if [ $feat_droproot = "1" ] && [ $try_libcap = "1" ] && \
test_code \
linuxcaps \
libcap \
'sys/types.h pwd.h sys/prctl.h sys/capability.h grp.h' \
'' '-lcap' \
'prctl(PR_SET_KEEPCAPS, 1);cap_set_proc(cap_from_text("cap_sys_time=ep"));'
then
add_def FEAT_LINUXCAPS
add_def FEAT_PRIVDROP
EXTRA_LIBS="$EXTRA_LIBS -lcap"
fi
@@ -522,7 +594,7 @@ then
add_def FEAT_RTC
fi
if [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
'ioctl(1, PTP_CLOCK_GETCAPS, 0);'
then
@@ -610,7 +682,7 @@ HASH_OBJ="hash_intmd5.o"
HASH_COMPILE=""
HASH_LINK=""
if [ $try_nss = "1" ]; then
if [ $feat_sechash = "1" ] && [ $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' \
@@ -621,11 +693,11 @@ if [ $try_nss = "1" ]; then
HASH_COMPILE="$test_cflags"
HASH_LINK="$test_link"
LIBS="$LIBS $HASH_LINK"
add_def GENERATE_SHA1_KEY
add_def FEAT_SECHASH
fi
fi
if [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]; then
if [ $feat_sechash = "1" ] && [ "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
@@ -633,7 +705,7 @@ if [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]; then
HASH_COMPILE="-I/usr/include/tomcrypt"
HASH_LINK="-ltomcrypt"
LIBS="$LIBS $HASH_LINK"
add_def GENERATE_SHA1_KEY
add_def FEAT_SECHASH
fi
fi
@@ -692,11 +764,17 @@ if [ "x$SETCHRONYVARDIR" != "x" ]; then
CHRONYVARDIR=$SETCHRONYVARDIR
fi
add_def DEBUG $debug
add_def DEFAULT_CONF_FILE "\"$SYSCONFDIR/chrony.conf\""
add_def DEFAULT_USER "\"$default_user\""
add_def MAIL_PROGRAM "\"$mail_program\""
common_features="`get_features ASYNCDNS IPV6 SECHASH`"
chronyc_features="`get_features READLINE`"
chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP DEBUG`"
add_def CHRONYC_FEATURES "\"$chronyc_features $common_features\""
add_def CHRONYD_FEATURES "\"$chronyd_features $common_features\""
echo "Features : $chronyd_features $chronyc_features $common_features"
if [ -f version.txt ]; then
add_def CHRONY_VERSION "\"`cat version.txt`\""
else

View File

@@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
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.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -1,583 +0,0 @@
#!/usr/bin/perl
# Copyright (C) Paul Elliott 2002
my($copyrighttext) = <<'EOF';
# Copyright (C) Paul Elliott 2002
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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.
# SEE COPYING FOR DETAILS
EOF
#modules we use.
use Socket;
use Getopt::Std;
use Net::DNS;
use Tie::Syslog;
use File::Temp qw/ :mktemp /;
use File::Copy;
local($res) = new Net::DNS::Resolver;
#dns lookup of IP address.
#returns ip or errorstring.
sub gethostaddr($) #get ip address from host
{
my($host) = shift;
$query = $res->search($host);
if ($query) {
foreach $rr ($query->answer) {
next unless $rr->type eq "A";
print $rr->address, "\n" if $pedebug;
return $rr->address;
}
} else {
print "query failed: ", $res->errorstring, "\n" if $pedebug;
return $res->errorstring;
}
}
#send messages to syslog
sub Log($$)
{
if ($log) {
my($level) = shift;
my($mess) =shift;
tie *MYLOG, 'Tie::Syslog',$level,$0,'pid','unix';
print MYLOG $mess;
untie *MYLOG;
}
}
#send message to output or syslog
#and die.
sub BadDie($)
{
my($myerr) =$!;
my($mess)=shift;
if($log){
tie *MYLOG, 'Tie::Syslog','local0.err',$0,'pid','unix';
print MYLOG $mess;
print MYLOG $myerr;
untie *MYLOG;
} else {
print "$mess\n$myerr\n";
}
die $mess;
}
sub isIpAddr($) #return true if looks like ip address
{
my($ip) = shift;
return 1 if ( $ip =~ m/$ipOnlyPAT/ );
return 0;
}
sub isHostname($) #return true if looks like ip address
{
my($ip) = shift;
return 1 if ( $ip =~ m/$hostnameOnlyPAT/ );
return 0;
}
#send commands to chronyc by piping.
sub chronyc($) #send commands to chronyc
{
my($command) = shift;
my($err) = "/var/tmp/chronyc.log";
my($chronyP) = "/usr/local/bin/chronyc";
open(CHRONY, "| $chronyP 1>$err 2>&1");
print CHRONY "$passwd$command\n";
close(CHRONY);
Log('local0.info',"chronyc command issued=$command");
#look at status lines till return bad.
open( IN, "<$err");
my($status);
while (<IN>) {
$status = $_;
unless ( m/\A200 OK/ ) {
last;
}
}
$status ="" if ( $status =~ m/\A200 OK/ );
close(IN);
unlink $err;
Log('local0.info',"chronyc results=$status");
return $status;
}
#common patterns
# an ip address patern
local($ipPAT) = qr/\d{1,3}(?:\.\d{1,3}){3}/;
# an hostname pattern
local($hostnamePAT) = qr/\w+(?:\.\w+)*/;
#line with hostname only
local($hostnameOnlyPAT) = qr/\A$hostnamePAT\Z/;
#line with ip address only
local($ipOnlyPAT) =qr/\A$ipPAT\Z/;
#options hash
my(%opts);
getopts('nuadslPSC', \%opts);
local($log) = ( $opts{'l'} ) ? 1 : 0;
my($offline) = !( $opts{'n'} ) ;
my($offlineS) = ( $opts{'n'} ) ? " " : " offline" ;
# paul elliotts secret debug var. no one will ever find out about it.
local($pedebug)=( ($ENV{"PAULELLIOTTDEBUG"}) or ($opts{P}) );
if ($opts{C}) {
print $copyrighttext;
exit 0;
}
print <<"EOF" unless $opts{'S'};
$0, Copyright (C) 2002 Paul Elliott
$0 comes with ABSOLUTELY NO WARRANTY; for details
invoke $0 -C. This is free software, and you are welcome
to redistribute it under certain conditions; invoke $0 -C
for details.
EOF
local($passwd);
# password to send to chronyc
my($pl) = $ENV{"CHRONYPASSWORD"};
#password comand to send to chronyc
if ( $pl ) {
$passwd = "password $pl\n";
} else {
$passwd = "";
}
print "passwd=$passwd\n" if ($pedebug);
my(%host2ip);
# hash of arrays. host2ip{$host}[0] is ip address for this host
# host2ip{$host}[1] is rest of paramenters for this host exc offline.
#if debuging do chrony.conf in current directory.
my($listfile) =( ($pedebug) ? "./chrony.conf" : "/etc/chrony.conf") ;
# This section reads in the old data about
# hostnames IP addresses and server parameters
# data is stored as it would be in chrony.conf
# file i.e.:
#># HOSTNAME
#>server IPADDR minpoll 5 maxpoll 10 maxdelay 0.4 offline
#
# the parameter offline is omitted if the -n switch is specified.
# first parameter is the filename of the file usually
# is /etc/DNSchrony.conf
# this is where we store the list of DNS hosts.
# hosts with static IP address shold be kept in chrony.conf
# this is header that marks dnyamic host section
my($noedithead)=<<'EOF';
## DNSchrony dynamic dns server section. DO NOT EDIT
## per entry FORMAT:
## |--------------------------------------------|
## |#HOSTNAME |
## |server IP-ADDRESS extra-params [ offline ] |
## |--------------------------------------------|
EOF
#patern that recognizes above.
my($noeditheadPAT) =
qr/\#\#\s+DNSchrony\s+dynamic\s+dns\s+server\s+section\.\s+DO\s+NOT\s+EDIT\s*/;
#end of header marker.
my($noeditheadend)=<<'EOF';
## END OF DNSchrony dynamic dns server section.
EOF
#pattern that matches above.
my($noeditheadendPAT)=
qr/\#\#\s+END\s+OF\s+DNSchrony\s+dynamic\s+dns\s+server\s+section.\s*/;
#array to hold non dns portion of chrony.conf
my(@chronyDconf);
my($ip);
my($rest);
my($host);
# for each entry in the list of hosts....
open(READIN, "<$listfile") or BadDie("Can not open $listfile");
# read till dynamic patern read save in @chronyDconf
while ( <READIN> ) {
my($line) = $_;
last if ( m/\A$noeditheadPAT\Z/ );
push(@chronyDconf,$line);
}
while ( <READIN> ) {
#end loop when end of header encountered
last if ( m/\A$noeditheadendPAT/ );
# parse the line giving ip address, extra pamamters, and host
#do host comment line first
($host) = m{
\A\#\s*
($hostnamePAT)
\s*\z
}xio;
#no match skip this line.
next unless ( $host );
# read next line
$_ = <READIN>;
# parse out ip address extra parameters.
($ip,$rest) =
m{
\A
\s*
server #server comand
\s+
($ipPAT) #ip address
(?ixo: \s )
\s*
(
(?(?!
(?iox: offline )? #skip to offline #
\s* #or #
\Z
).)*
)
(?ixo:
\s*
(?ixo: offline )? #consume to #
\s*
\Z
)
}xio ;
#if failure again.
next unless ( $ip );
$rest =~ s/\s*\z//; #remove trail blanks
#from parameters
# store the data in the list
# key is host name value is
# array [0] is ip address
# [1] is other parameters
$host2ip{$host} = [$ip,$rest] ;
print "ip=$ip rest=$rest host=$host<\n" if $pedebug;
}
#read trailing line into @chronyDconf
while ( <READIN> ) {
push(@chronyDconf,$_);
}
close(READIN) or BadDie("can not close $listfile");
#if the add command:
# command can be HOST=IPADDRESS OTHER_PARAMETERS
# means add the server trust the ip address geven with out a dns lookup
# good for when dns is down but we know the ip addres
# or
# HOST OTHER_PARAMETERS
#we lookup the ip address with dns.
if ($opts{'a'}) {
my($param)= shift;
# parse the param is it hostname
if ( ($host,$ip) = $param =~ m/\A($hostnamePAT)=($ipPAT)\Z/ ) {
printf "ip=$ip host=$host\n" if ($pedebug);
} else {
$host = $param;
# get the ip address
$ip = gethostaddr($host);
if ( ! isIpAddr($ip) or ! isHostname($host) ) {
print "query failed: ", $ip, "host=$host\n" if $pedebug;
exit 1;
}
}
printf "ip=$ip host=$host\n" if ($pedebug);
# add the server using chronyc
my($status) = chronyc("add server $ip $rest");
if ($status) { #chronyc error
print "chronyc failed, status=$status\n";
exit 1;
}
# get rest of arguements
$rest = join( ' ', @ARGV);
print "rest=$rest\n" if ($pedebug);
#save node in hash
$host2ip{$host} = [$ip,$rest] ;
print "ip=$ip rest=$rest host=$host<\n" if $pedebug;
}
#delete command if arguement is ip address
#just delete it
#if a hostname look it up
#then delete it.
if ($opts{'d'}) {
$host = shift;
#get host name is it ap address
if ( isIpAddr($host) ) { # if ip address
my($hostIT);
my($found) =0;
foreach $hostIT (keys(%host2ip) ) { #search for match
if ( $host2ip{$hostIT}[0] eq $host) {
$found=1; #record match
}
} #end of search
if ($found) { #if match found
my($status) = chronyc("delete $host"); #chronyc
if ($status) { #chronyc error
print "chronyc failed, status=$status\n";
exit 1;
} else { #reiterate
foreach $hostIT (keys(%host2ip) ) {
if ( $host2ip{$hostIT}[0] eq $host) {
delete $host2ip{$hostIT}; #deleting match hosts
}
}
}
}
} else { #else not ip address
#must be hostname
if ( ! $host2ip{$host} ) {
print "No such host as $host listed\n";
exit 1;
}
#get ip address
$ip=gethostaddr($host);
if ( ! isIpAddr($ip) ) { #no ip address
print "query failed: ", $ip, "\n" if $pedebug;
exit 1;
}
printf "ip=$ip host=$host\n" if ($pedebug);
my($listed_host_ip) = $host2ip{$host}[0]; # get the ip address saved
if ( $ip ne $listed_host_ip) {
print
"Info: listed host ip=>$listed_host_ip".
"< is different from DNS ip=>$ip<\n";
$ip = $listed_host_ip;
}
# delete the server
my($status) = chronyc("delete $listed_host_ip\n");
if ($status) {
print "chronyc failed, status=$status\n";
exit 1;
}
#delete table entry
delete$host2ip{$host};
}
}
#update for each host who's dns ip address has changed
#delete the old server and add the new. update the record.
if ($opts{'u'}) {
my($command);
my(%prospective); # store new IP address we
#are thinking of changing.
Log('local0.info',
"Now searching for modified DNS entries.");
foreach $host (keys(%host2ip)) { #for each listed host
my($old_ip) = $host2ip{$host}[0]; #get old ip
$rest = $host2ip{$host}[1]; #extra params
$ip = gethostaddr($host); #get new ip from dns
#if error
if ( ! isIpAddr($ip) or ! isHostname($host) ) {
print "query failed: ", $ip, "host=$host\n";
Log('local0.err',"query failed: ". $ip . "host=$host");
exit 1;
}
next if($ip eq $old_ip); #if ip not changed, skip
Log('local0.info',"Ip address for $host has changed. Old IP address=".
"$old_ip, new IP address=$ip");
# add command to delete old host, add the new.
$command = $command . "delete $old_ip\n" .
"add server $ip $rest\n";
# we are now thinking about changing this host ip
$prospective{$host} = [$ip,$rest];
}
# submit all the accumulated chronyc commands if any.
if ($command) {
$status = chronyc($command);
if ($status) {
print "chronyc failed, status=$status\n";
Log('local0.err',"query failed: ". $ip . "host=$host");
exit 1;
}
} else { #if no commands exit
exit 0; #because no rewrite of file needed
}
#copy prospective modifications back into main table.
#we now know that all these mods were done with chronyc
foreach $host (keys(%prospective)) {
my($ip) = $prospective{$host}[0];
$rest = $prospective{$host}[1];
$host2ip{$host} = [$ip,$rest];
}
}
#starting for each entry we have read in from the old list
# add the server in chronyc
# this option is seldom used.
if ($opts{'s'}) {
my($command)="";
foreach $host (keys(%host2ip)) {
$command = $command . "add server $host2ip{$host}[0] ".
"$host2ip{$host}[1]\n";
}
my($status) = chronyc($command);
if ($status) {
print "chronyc failed, status=$status\n";
exit 1;
}
}
# write out the data file in format
#># HOSTNAME
#>server IPADDRESS extra parameters [offline]
# offline is omitted if -n switch is specified.
my(@value);
my($such);
{
# to start out we write to temporary file.
(my($writeout) , my($outname)) = mkstemp( "${listfile}.outXXXXXXX");
$outname or BadDie("can not open for $listfile");
# save the chrony.conf part!
# and write the DYNAMIC header
print $writeout @chronyDconf, $noedithead;
# for each entry
foreach $host (keys(%host2ip) ){
#write the record
# write the comment that indicates the hostname
# and the server command.
print $writeout
"\# $host\nserver $host2ip{$host}[0] $host2ip{$host}[1]${offlineS}\n" ;
print
"server $host2ip{$host}[0] $host2ip{$host}[1]${offlineS}\# $host\n"
if $pedebug;
}
#WRITE THE end of dnyamic marker comment
print $writeout $noeditheadend;
# close the output file which was a temporary file.
close($writeout) or BadDie("can not close $outname");
# we now begin a intracate dance to make the the temporary
# the main chrony.conf
#
# if there is a chrony.conf.BAK save it to a temporary.
# rename chrony.conf to chrony.conf.BAK
# rename the temporary to chrony.conf
# if there already was a chrony.conf.BAK, unlink the copy of this.
my($backname) = "$listfile\.BAK";
my($backplain) = ( -f $backname );
my($saveback);
#if chrony.conf.BAK exists rename to a temporary.
if ($backplain ) {
$saveback = mktemp("${backname}.bakXXXXXXX");
move($backname,$saveback) or
BadDie "unable to move $backname to $savename";
}
# rename old chrony.conf to chrony.conf.BAK
move($listfile,$backname) or
BadDie "unable to move $listfile to $backname";
# rename our output to chrony.conf
move($outname,$listfile) or
BadDie "unable to move $outname to $listfile";
#if there was a temporary chrony.conf.BAK that we saved to temp
#unlink it
unlink($saveback) or BadDie "unable to unlink $saveback" if($backplain);
}

View File

@@ -1,21 +0,0 @@
#!/usr/bin/bash
# $1 is chrony password.
# $2 is hostname to add or hostname=ipaddres
# $3-$9 is rest of extra server parameters
FIRST="$1"
HOST="$2"
shift 2
#remaining parameters a the other paramaters to server command
#excluding "offline"
ARGS="$*"
#if none use default taken from chrony documentation.
DEF="minpoll 5 maxpoll 10 maxdelay 0.4"
DARGS=${ARGS:-$DEF}
CHRONYPASSWORD=$FIRST \
/usr/local/bin/DNSchrony.pl -a "$HOST" "$DARGS"

View File

@@ -1,7 +0,0 @@
#!/usr/bin/bash
# $1 is chrony password.
# $2 host to be deleted if ip nn.n.n.n then no DNS used
CHRONYPASSWORD=$1 \
/usr/local/bin/DNSchrony.pl -d $2

View File

@@ -1,7 +0,0 @@
#!/usr/bin/bash
# $1 is chrony password.
CHRONYPASSWORD=$1 \
/usr/local/bin/DNSchrony.pl -ulS

View File

@@ -1,166 +0,0 @@
Copyright (C) Paul Elliott 2002
DNSchrony.pl version -2.0
Problem: If you look at the list of secondary NTP servers:
http://www.eecis.udel.edu/~mills/ntp/clock2.htm
you will find statements like this:
"Note: IP addresses are subject to change; please use DNS"
These servers represent a problem for chrony. Chrony is a program
designed to work on hosts with an intermittent connection to the
internet. Often no DNS is available when chrony starts. As chrony
is currently designed, chronyd never sees a DNS host name. If a
user specifies one when using chronyc's "add server" command, the
DNS lookup is done by chronyc and an IP address is passed to chronyd.
One can imagine I suppose, a redesign to chrony in which chronyd
keeps track of DNS changes. But this has problems, all the time
chronyd is fooling around with DNS, it would not be keeping track
of its prime function, what the clocks and NTP servers are saying.
This could result in poorer performance. Or perhaps you say that
chronyd should be multi threaded. One thread to fool with DNS
and another to keep track of time. But this introduces a great
deal of complexity, and complexity is the enemy of elegant robust
code. Besides, Richard probably has better things to do.
I have attempted to address this problem with a humble perl script,
which I now release under the GPL: DNSchrony.pl
PLEA FOR HELP FROM EXPERIENCED PERL HACKERS.
Please go thru the code and find errors and improvements.
I am not quite an polished perl hacker. Please fix bugs and
make improvements. It needs better documentation. Someone
who knows how, put in some POD.
END OF PLEA
Philosophy of DNSchrony.pl: keep a list of servers that use
DNS. From time to time, hopefully when DNS is up, go thru
the list lookup all the hostnames and see if any ip addresses have
changed. If any have changed, update our list and do chronyc
"delete" and "add server" commands so that chronyd now talks to
the right NTP server.
Additional nuance: keep the list in /etc/chrony.conf in the
form of comments starting with "#" and "server" commands
legal in a chrony.conf file. Format of a list entry:
# hostname
server IP-ADDRESS extra server parameters
These entries are delimited by special comments that allow
DNSchrony.pl to find them and also tell humans not to mess with them.
Example of such a section of a chrony.conf file:
dumpdir /var/log/chrony
rtcfile /etc/chrony.rtc
## DNSchrony dynamic dns server section. DO NOT EDIT
## per entry FORMAT:
## |--------------------------------------------|
## |#HOSTNAME |
## |server IP-ADDRESS extra-params [ offline ] |
## |--------------------------------------------|
# tock.greyware.com
server 208.14.208.44 minpoll 5 maxpoll 10 maxdelay 0.4 offline
# tick.greyware.com
server 208.14.208.19 minpoll 5 maxpoll 10 maxdelay 0.4 offline
# ntppub.tamu.edu
server 128.194.254.9 minpoll 5 maxpoll 10 maxdelay 0.4 offline
## END OF DNSchrony dynamic dns server section.
This allows the list of dynamic DNS servers to be preserved
when chronyd is stoped/started.
All servers that do not have ip addresses subject to change
should be put in the regular part of chrony.conf as described
in the chrony documentation.
Security philosophy: DNSchrony does no security checking but
relies on other security factors.
Users without the privilege to modify /etc/chrony.conf and the
directory /etc will be unable to use DNSchrony to do so, because
of file protections. DNSchrony passes thru passwords to chronyc.
Users that do not know the correct chronyc password will be
unable to get chronyd do do anything. Thus, DNSchrony passes
the buck to these other security features.
INSTALLATION:
copy the files: DNSchronyADD DNSchronyUPDATE DNSchronyDELETE DNSchrony.pl
to /usr/local/bin. Backup the file /etc/chrony.conf leave hosts
with static ip addresses in this file.
DNSchrony uses the following perl modules. See that they are installed.
Get them from CPAN if needed.
Net::DNS, Tie::Syslog, Getopt::Std, Socket, File.
Cause DNSchronyUPDATE bash script to run from time to time when DNS
is working. If you have a dialup, one way to do this would be to
modify your /etc/ppp/ip-up.local file as follows:
cat <<EOF | /usr/local/bin/chronyc
password mysecret
online
EOF
# update all of the dynamic servers and save the result.
# do not wait for response
nohup /usr/local/bin/DNSchronyUPDATE mysecret >/dev/null 2>&1 &
Since this file contains the chronyc password you will want to set the
file permissions so that just everybody will not be able to read
it. But you already did that when you put in the chronyc command. Any
other way to make DNSchronyUPDATE run perodicly when DNS is up will
also work.
To add a server with a varying IP address one could run:
/usr/local/bin/DNSchronyADD mysecret tock.greyware.com
or if you want to specify different server parameters you
could say:
/usr/local/bin/DNSchronyADD mysecret tock.greyware.com "minpoll 10 maxpoll 20 maxdelay 0.8"
The DNSchronyADD's default for these parameters is:
"minpoll 5 maxpoll 10 maxdelay 0.4" values that are often shown
as examples in the chrony documentation.
If DNS is not running now but you know the IP address, you can say:
/usr/local/bin/DNSchronyADD mysecret tock.greyware.com=208.14.208.44
Of course, the IP address will be checked next time DNSchronyUPDATE
runs.
To delete dynamic DNS a server:
/usr/local/bin/DNSchronyDELETE mysecret tock.greyware.com
To change parameters delete and re-add.
Of course, in all of the above "mysecret" is your chronyc password
which SHOULD NOT BE "mysecret".
----------------------------------------------
DNSchrony.pl is covered by the GPL
# Copyright (C) Paul Elliott 2002
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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.
# SEE COPYING FOR DETAILS

View File

@@ -1,22 +0,0 @@
#example file /etc/ppp/ip-up.local
#originally from SuSE distribution
#modified for chrony
cat <<EOF | /usr/local/bin/chronyc
password mysecret
online
EOF
# update all of the dynamic servers and save the result.
# do not wait for response
nohup /usr/local/bin/DNSchronyUPDATE mysecret >/dev/null 2>&1 &
#other stuff who knows?
# The following lines added for Linux-HA support # Heartbeat
DEVFILE=`echo $DEVICE | sed -e 's!^/dev/!!' -e 's!/!.!g'` # Heartbeat
OUTFILE=/var/run/ppp.d/$DEVFILE # Heartbeat
( # Heartbeat
echo "$IPREMOTE" # Heartbeat
echo "$IFNAME" # Heartbeat
echo "$PPPD_PID" # Heartbeat
echo "$IPLOCAL" # Heartbeat
) > $OUTFILE # Heartbeat

273
doc/faq.adoc Normal file
View File

@@ -0,0 +1,273 @@
:toc:
:numbered:
Frequently Asked Questions
==========================
== Chrony compared to other programs
=== How does +chrony+ compare to +ntpd+?
+chrony+ can usually synchronise the system clock faster and with better time
accuracy, but it doesn't implement all NTP features, e.g. broadcast/multicast
mode, or authentication based on public-key cryptography. For a more detailed
comparison, see the http://chrony.tuxfamily.org/comparison.html[comparison
page] on the chrony website and section
http://chrony.tuxfamily.org/manual.html#Comparison-with-ntpd[Comparison with
ntpd] in the manual.
If your computer connects to the 'net only for few minutes at a time, you turn
your Linux computer off or suspend it frequently, the clock is not very stable
(e.g. it is a virtual machine), or you want to use NTP on an isolated network
with no hardware clocks in sight, +chrony+ will probably work much better for
you.
The original reason +chrony+ was written was that ntpd (called xntpd at the
time) could not to do anything sensible on a PC which was connected to the 'net
only for about 5 minutes once or twice a day, mainly to upload/download email
and news. The requirements were
* slew the time to correct it when going online and NTP servers
become visible
* determine the rate at which the computer gains or loses time and
use this information to keep it reasonably correct between connects
to the 'net. This has to be done using a method that does not care
about the intermittent availability of the references or the fact
the computer is turned off between groups of measurements.
* maintain the time across reboots, by working out the error and
drift rate of the computer's real-time clock and using this
information to set the system clock correctly at boot up.
Also, when working with isolated networks with no true time references at all
ntpd was found to give no help with managing the local clock's gain/loss rate
on the NTP master node (which was set from watch). Some automated support was
added to +chrony+ to deal with this.
== Configuration issues
=== I have several computers on a LAN. Should be all clients of an external server?
The best configuration is usually to make one computer the master, with
the others as clients of it. Add a +local+ directive to the master's
'chrony.conf' file. This configuration will be better because
* the load on the external connection is less
* the load on the external NTP server(s) is less
* if your external connection goes down, the computers on the LAN
will maintain a common time with each other.
=== Must I specify servers by IP address if DNS is not available on chronyd start?
No. Starting from version 1.25, +chronyd+ will keep trying to resolve
the hostnames specified in the +server+ and +peer+ directives in
increasing intervals until it succeeds. The +online+ command can be
issued from +chronyc+ to try to resolve them immediately.
=== How can I make chronyd more secure?
If you don't need to serve time to NTP clients or peers, you can add +port 0+
to the 'chrony.conf' file to completely disable the NTP server functionality
and prevent NTP requests from reaching +chronyd+. Starting from version 2.0,
the NTP server port is open only when client access is allowed by the +allow+
directive or command, an NTP peer is configured, or the +broadcast+ directive
is used.
If you don't need to use +chronyc+ remotely, you can add the following
directives to the configuration file to bind the command sockets to the
loopback interface. This is done by default since version 2.0.
----
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
----
If you don't need to use +chronyc+ at all, you can disable the command sockets
by adding +cmdport 0+ to the configuration file.
On Linux, if +chronyd+ is compiled with support for Linux capabilities
(available in the libcap library), you can specify an unprivileged user with
the +-u+ option or +user+ directive in the 'chrony.conf' file to drop root
privileges after start. The configure option +--with-user+ can be used to drop
the privileges by default.
=== How can I improve the accuracy of the system clock with NTP sources?
Select NTP servers that are well synchronised, stable and close to your
network. It's better to use more than one server, three or four is usually
recommended as the minimum, so +chronyd+ can detect falsetickers and combine
measurements from multiple sources.
There are also useful options which can be set in the +server+ directive, they
are +minpoll+, +maxpoll+, +polltarget+, +maxdelay+, +maxdelayratio+ and
+maxdelaydevratio+.
The first three options set the minimum and maximum allowed polling interval,
and how should be the actual interval adjusted in the specified range. Their
default values are 6 (64 seconds) for +minpoll+, 10 (1024 seconds) for
+maxpoll+ and 6 (samples) for +polltarget+. The default values should be used
for general servers on the internet. With your own NTP servers or if have
permission to poll some servers more frequently, setting these options for
shorter polling intervals may significantly improve the accuracy of the system
clock.
The optimal polling interval depends on many factors, including the ratio
between the wander of the clock and the network jitter (sometimes expressed in
NTP documents as the Allan intercept), the temperature sensitivity of the
crystal oscillator and the maximum rate of change of the temperature.
An example of the directive for an NTP server on the internet that you are
allowed to poll frequently could be
----
server foo.example.net minpoll 4 maxpoll 6 polltarget 16
----
An example using very short polling intervals for a server located in the same
LAN could be
----
server ntp.local minpoll 2 maxpoll 4 polltarget 30
----
The maxdelay options are useful to ignore measurements with larger delay (e.g.
due to congestion in the network) and improve the stability of the
synchronisation. The +maxdelaydevratio+ option could be added to the example
with local NTP server
----
server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
----
== Computer is not synchronising
This is the most common problem. There are a number of reasons, see the
following questions.
=== Behind a firewall?
If there is a firewall between you and the NTP server you're trying to use, the
packets may be blocked. Try using a tool like wireshark or tcpdump to see if
you're getting responses from the server. If you have an external modem, see
if the receive light blinks straight after the transmit light (when the link is
quiet apart from the NTP traffic.) Try adding +log measurements+ to the
'chrony.conf' file and look in the 'measurements.log' file after +chrony+ has
been running for a short period. See if any measurements appear.
=== Are NTP servers specified with the +offline+ option?
Check that you're using +chronyc+\'s +online+ and +offline+ commands
appropriately. Again, check in 'measurements.log' to see if you're getting any
data back from the server.
== Issues with +chronyc+
=== I keep getting the error +506 Cannot talk to daemon+
When accessing +chronyd+ remotely, 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 and an appropriate 'bindcmdaddress'
directive. This 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
123/udp and 323/udp are listening. If +chronyd+ is not running, you may have a
problem with the way you are trying to start it (e.g. at boot time).
Perhaps you have a firewall set up in a way that blocks packets on port
323/udp. You need to amend the firewall configuration in this case.
=== Is the +chronyc+ / +chronyd+ protocol documented anywhere?
Only by the source code :-) See 'cmdmon.c' (+chronyd+ side) and 'client.c'
(+chronyc+ side).
== Real-time clock issues
=== What is the real-time clock (RTC)?
This is the clock which keeps the time even when your computer is turned off.
It works with 1 second resolution. +chronyd+ can monitor the rate at which the
real-time clock gains or loses time, and compensate for it when you set the
system time from it at the next reboot. See the documentation for details.
=== I want to use +chronyd+'s real-time clock support. Must I disable hwclock?
The hwclock program is often set-up by default in the boot and shutdown scripts
with many Linux installations. If you want to use +chronyd+'s real-time clock
support, the important thing is to disable hwclock in the shutdown procedure.
If you don't, it will over-write the RTC with a new value, unknown to
+chronyd+. At the next reboot, +chronyd+ will compensate this (wrong) time
with its estimate of how far the RTC has drifted whilst the power was off,
giving a meaningless initial system time.
There is no need to remove hwclock from the boot process, as long as +chronyd+
is started after it has run.
=== I just keep getting the +513 RTC driver not running+ message
For the real time clock support to work, you need the following three
things
* a kernel that is supported (e.g. 2.2 onwards)
* enhanced RTC support compiled into the kernel
* an +rtcfile+ directive in your 'chrony.conf' file
== Microsoft Windows
=== Does +chrony+ support Windows?
No. The +chronyc+ program (the command-line client used for configuring
+chronyd+ while it is running) has been successfully built and run under
Cygwin in the past. +chronyd+ is not portable, because part of it is
very system-dependent. It needs adapting to work with Windows'
equivalent of the adjtimex() call, and it needs to be made to work as a
service.
=== Are there any plans to support Windows?
We have no plans to do this. Anyone is welcome to pick this work up and
contribute it back to the project.
== NTP-specific issues
=== Can +chrony+ be driven from broadcast NTP servers?
No, this NTP mode is not implemented yet.
=== Can chronyd transmit broadcast NTP packets (e.g. to synchronise other computers on a private LAN)?
Yes. Starting from version 1.17, +chrony+ has this capability.
=== Can +chrony+ keep the system clock a fixed offset away from real time?
This is not possible as the program currently stands.
=== What happens if the network connection is dropped without using +chronyc+'s +offline+ command first?
+chronyd+ will keep trying to access the server(s) that it thinks are online.
When the network is connected again, it will take some time (on average half of
the current polling interval) before new measurements are made and the clock is
corrected. If the servers were set to offline and the +online+ command was
issued when the network was connected, +chronyd+ would make new measurements
immediately.
The +auto_offline+ option to the +server+ entry in the 'chrony.conf' file may
be useful to switch the servers to the offline state automatically.
== Linux-specific issues
=== I get +Could not open /dev/rtc, Device or resource busy+ in my syslog file
Some other program running on the system may be using the device.
== Solaris-specific issues
=== I get an error message about not being able to open kvm to change dosynctodr
(The dosynctodr variable controls whether Solaris couples the equivalent
of its BIOS clock into its system clock at regular intervals). The
Solaris port of +chrony+ was developed in the Solaris 2.5 era. Some
aspect of the Solaris kernel has changed which prevents the same
technique working. We no longer have root access to any Solaris
machines to work on this, and we are reliant on somebody developing the
patch and testing it.

View File

@@ -0,0 +1,12 @@
# Use public NTP servers from the pool.ntp.org project.
pool pool.ntp.org iburst
# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 10 seconds.
makestep 10 3
# Enable kernel synchronization of the real-time clock (RTC).
rtcsync

View File

@@ -1,46 +1,40 @@
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
server 0.pool.ntp.org iburst
server 1.pool.ntp.org iburst
server 2.pool.ntp.org iburst
server 3.pool.ntp.org iburst
# Ignore stratum in source selection.
stratumweight 0
pool pool.ntp.org iburst
# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift
# Enable kernel RTC synchronization.
rtcsync
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 10 seconds.
makestep 10 3
# Enable kernel synchronization of the real-time clock (RTC).
rtcsync
# 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
# Specify file containing keys for NTP and command authentication.
keyfile /etc/chrony.keys
# Specify the key used as password for chronyc.
# Specify key number for command authentication.
commandkey 1
# Generate command key if missing.
# Generate new command key on start if missing.
generatecommandkey
# Disable logging of client accesses.
noclientlog
# Send a message to syslog if a clock adjustment is larger than 0.5 seconds.
# Send message to syslog when clock adjustment is larger than 0.5 seconds.
logchange 0.5
# Specify directory for log files.
logdir /var/log/chrony
# Select which information is logged.
#log measurements statistics tracking

View File

@@ -43,25 +43,29 @@
# you can access at http://support.ntp.org/bin/view/Servers/WebHome or
# you can use servers from the pool.ntp.org project.
! server 0.pool.ntp.org iburst
! server 1.pool.ntp.org iburst
! server 2.pool.ntp.org iburst
! server foo.example.net iburst
! server bar.example.net iburst
! server baz.example.net iburst
! pool 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 0.pool.ntp.org offline
! server 1.pool.ntp.org offline
! server 2.pool.ntp.org offline
! server foo.example.net offline
! server bar.example.net offline
! server baz.example.net offline
! pool 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
# have the 'front-line' interface to the public NTP servers, you can
# 'peer' these machines together to increase robustness.
! peer ntp0.my-company.com
! peer foo.example.net
# There are other options to the 'server' and 'peer' directives that you
# might want to use. For example, you can ignore measurements whose
@@ -107,6 +111,7 @@ keyfile /etc/chrony.keys
commandkey 1
# With this directive a random password will be generated automatically.
generatecommandkey
# chronyd can save the measurement history for the servers to files when
@@ -233,13 +238,18 @@ generatecommandkey
# several people, you need to set up a mailing list or sendmail alias
# for them and use the address of that.)
! mailonchange wibble@foobar.org 0.5
! mailonchange wibble@foo.example.net 0.5
#######################################################################
### COMMAND ACCESS
# The program chronyc is used to show the current operation of chronyd
# and to change parts of its configuration whilst it is running.
# By default chronyd binds to the loopback interface. Uncomment the
# following lines to allow receiving command packets from remote hosts.
! bindcmdaddress 0.0.0.0
! bindcmdaddress ::
# Normally, chronyd will only allow connections from chronyc on the same
# machine as itself. This is for security. If you have a subnet
# 192.168.*.* and you want to be able to use chronyc from any machine on

View File

@@ -45,7 +45,6 @@ cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
%{_sbindir}/chronyd
%{_bindir}/chronyc
%{_infodir}/chrony.info*
%{_mandir}/man1/chrony.1.gz
%{_mandir}/man1/chronyc.1.gz
%{_mandir}/man5/chrony.conf.5.gz
%{_mandir}/man8/chronyd.8.gz

2
hash.h
View File

@@ -38,4 +38,6 @@ extern unsigned int HSH_Hash(int id,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len);
extern void HSH_Finalise(void);
#endif

View File

@@ -62,3 +62,8 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
return 16;
}
void
HSH_Finalise(void)
{
}

View File

@@ -87,3 +87,17 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
return ret;
}
void
HSH_Finalise(void)
{
int i;
for (i = 0; hashes[i].name; i++) {
if (hashes[i].context)
NSSLOWHASH_Destroy(hashes[i].context);
}
if (ictx)
NSSLOW_Shutdown(ictx);
}

View File

@@ -114,3 +114,8 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
return len;
}
void
HSH_Finalise(void)
{
}

164
keys.c
View File

@@ -30,6 +30,7 @@
#include "sysincl.h"
#include "array.h"
#include "keys.h"
#include "cmdparse.h"
#include "conf.h"
@@ -40,30 +41,27 @@
typedef struct {
unsigned long id;
uint32_t id;
char *val;
int len;
int hash_id;
int auth_delay;
} Key;
#define MAX_KEYS 256
static int n_keys;
static Key keys[MAX_KEYS];
static ARR_Instance keys;
static int command_key_valid;
static int command_key_id;
static uint32_t command_key_id;
static int cache_valid;
static unsigned long cache_key_id;
static uint32_t cache_key_id;
static int cache_key_pos;
/* ================================================== */
static int
generate_key(unsigned long key_id)
generate_key(uint32_t key_id)
{
#ifdef GENERATE_SHA1_KEY
#ifdef FEAT_SECHASH
unsigned char key[20];
const char *hashname = "SHA1";
#else
@@ -102,7 +100,7 @@ generate_key(unsigned long key_id)
return 0;
}
fprintf(f, "\n%lu %s HEX:", key_id, hashname);
fprintf(f, "\n%"PRIu32" %s HEX:", key_id, hashname);
for (i = 0; i < sizeof (key); i++)
fprintf(f, "%02hhX", key[i]);
fprintf(f, "\n");
@@ -111,17 +109,32 @@ generate_key(unsigned long key_id)
/* Erase the key from stack */
memset(key, 0, sizeof (key));
LOG(LOGS_INFO, LOGF_Keys, "Generated key %lu", key_id);
LOG(LOGS_INFO, LOGF_Keys, "Generated key %"PRIu32, key_id);
return 1;
}
/* ================================================== */
static void
free_keys(void)
{
unsigned int i;
for (i = 0; i < ARR_GetSize(keys); i++)
Free(((Key *)ARR_GetElement(keys, i))->val);
ARR_SetSize(keys, 0);
command_key_valid = 0;
cache_valid = 0;
}
/* ================================================== */
void
KEY_Initialise(void)
{
n_keys = 0;
keys = ARR_CreateInstance(sizeof (Key));
command_key_valid = 0;
cache_valid = 0;
KEY_Reload();
@@ -137,12 +150,22 @@ KEY_Initialise(void)
void
KEY_Finalise(void)
{
free_keys();
ARR_DestroyInstance(keys);
}
/* ================================================== */
static Key *
get_key(unsigned int index)
{
return ((Key *)ARR_GetElements(keys)) + index;
}
/* ================================================== */
static int
determine_hash_delay(unsigned long key_id)
determine_hash_delay(uint32_t key_id)
{
NTP_Packet pkt;
struct timeval before, after;
@@ -151,7 +174,7 @@ determine_hash_delay(unsigned long key_id)
for (i = 0; i < 10; i++) {
LCL_ReadRawTime(&before);
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_SIZE,
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_LENGTH,
(unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
LCL_ReadRawTime(&after);
@@ -165,7 +188,7 @@ determine_hash_delay(unsigned long key_id)
/* Add on a bit extra to allow for copying, conversions etc */
min_usecs += min_usecs >> 4;
DEBUG_LOG(LOGF_Keys, "authentication delay for key %lu: %ld useconds", key_id, min_usecs);
DEBUG_LOG(LOGF_Keys, "authentication delay for key %"PRIu32": %ld useconds", key_id, min_usecs);
return min_usecs;
}
@@ -195,18 +218,14 @@ compare_keys_by_id(const void *a, const void *b)
void
KEY_Reload(void)
{
int i, line_number;
unsigned int i, line_number;
FILE *in;
unsigned long key_id;
uint32_t key_id;
char line[2048], *keyval, *key_file;
const char *hashname;
Key key;
for (i=0; i<n_keys; i++) {
Free(keys[i].val);
}
n_keys = 0;
command_key_valid = 0;
cache_valid = 0;
free_keys();
key_file = CNF_GetKeysFile();
line_number = 0;
@@ -232,22 +251,22 @@ KEY_Reload(void)
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);
key.hash_id = HSH_GetHashId(hashname);
if (key.hash_id < 0) {
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %"PRIu32, 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);
key.len = UTI_DecodePasswordFromText(keyval);
if (!key.len) {
LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %"PRIu32, 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++;
key.id = key_id;
key.val = MallocArray(char, key.len);
memcpy(key.val, keyval, key.len);
ARR_AppendElement(keys, &key);
}
fclose(in);
@@ -255,50 +274,50 @@ KEY_Reload(void)
/* 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);
qsort(ARR_GetElements(keys), ARR_GetSize(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", keys[i].id);
}
for (i = 1; i < ARR_GetSize(keys); i++) {
if (get_key(i - 1)->id == get_key(i)->id)
LOG(LOGS_WARN, LOGF_Keys, "Detected duplicate key %"PRIu32, get_key(i - 1)->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);
}
for (i = 0; i < ARR_GetSize(keys); i++)
get_key(i)->auth_delay = determine_hash_delay(get_key(i)->id);
}
/* ================================================== */
static int
lookup_key(unsigned long id)
lookup_key(uint32_t id)
{
Key specimen, *where;
Key specimen, *where, *keys_ptr;
int pos;
keys_ptr = ARR_GetElements(keys);
specimen.id = id;
where = (Key *) bsearch((void *)&specimen, (void *)keys, n_keys, sizeof(Key), compare_keys_by_id);
where = (Key *)bsearch((void *)&specimen, keys_ptr, ARR_GetSize(keys),
sizeof (Key), compare_keys_by_id);
if (!where) {
return -1;
} else {
pos = where - keys;
pos = where - keys_ptr;
return pos;
}
}
/* ================================================== */
static int
get_key_pos(unsigned long key_id)
static Key *
get_key_by_id(uint32_t key_id)
{
int position;
if (cache_valid && key_id == cache_key_id)
return cache_key_pos;
return get_key(cache_key_pos);
position = lookup_key(key_id);
@@ -306,14 +325,16 @@ get_key_pos(unsigned long key_id)
cache_valid = 1;
cache_key_pos = position;
cache_key_id = key_id;
return get_key(position);
}
return position;
return NULL;
}
/* ================================================== */
unsigned long
uint32_t
KEY_GetCommandKey(void)
{
if (!command_key_valid) {
@@ -326,61 +347,56 @@ KEY_GetCommandKey(void)
/* ================================================== */
int
KEY_KeyKnown(unsigned long key_id)
KEY_KeyKnown(uint32_t key_id)
{
return get_key_pos(key_id) >= 0;
return get_key_by_id(key_id) != NULL;
}
/* ================================================== */
int
KEY_GetAuthDelay(unsigned long key_id)
KEY_GetAuthDelay(uint32_t key_id)
{
int key_pos;
Key *key;
key_pos = get_key_pos(key_id);
key = get_key_by_id(key_id);
if (key_pos < 0) {
if (!key)
return 0;
}
return keys[key_pos].auth_delay;
return key->auth_delay;
}
/* ================================================== */
int
KEY_GenerateAuth(unsigned long key_id, const unsigned char *data, int data_len,
KEY_GenerateAuth(uint32_t key_id, const unsigned char *data, int data_len,
unsigned char *auth, int auth_len)
{
int key_pos;
Key *key;
key_pos = get_key_pos(key_id);
key = get_key_by_id(key_id);
if (key_pos < 0) {
if (!key)
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);
return UTI_GenerateNTPAuth(key->hash_id, (unsigned char *)key->val,
key->len, data, data_len, auth, auth_len);
}
/* ================================================== */
int
KEY_CheckAuth(unsigned long key_id, const unsigned char *data, int data_len,
KEY_CheckAuth(uint32_t key_id, const unsigned char *data, int data_len,
const unsigned char *auth, int auth_len)
{
int key_pos;
Key *key;
key_pos = get_key_pos(key_id);
key = get_key_by_id(key_id);
if (key_pos < 0) {
if (!key)
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);
return UTI_CheckNTPAuth(key->hash_id, (unsigned char *)key->val,
key->len, data, data_len, auth, auth_len);
}

14
keys.h
View File

@@ -27,20 +27,22 @@
#ifndef GOT_KEYS_H
#define GOT_KEYS_H
#include "sysincl.h"
extern void KEY_Initialise(void);
extern void KEY_Finalise(void);
extern void KEY_Reload(void);
extern unsigned long KEY_GetCommandKey(void);
extern uint32_t 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_GetKey(uint32_t key_id, char **key, int *len);
extern int KEY_KeyKnown(uint32_t key_id);
extern int KEY_GetAuthDelay(uint32_t key_id);
extern int KEY_GenerateAuth(unsigned long key_id, const unsigned char *data,
extern int KEY_GenerateAuth(uint32_t key_id, const unsigned char *data,
int data_len, unsigned char *auth, int auth_len);
extern int KEY_CheckAuth(unsigned long key_id, const unsigned char *data,
extern int KEY_CheckAuth(uint32_t key_id, const unsigned char *data,
int data_len, const unsigned char *auth, int auth_len);
#endif /* GOT_KEYS_H */

120
local.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011, 2014
* Copyright (C) Miroslav Lichvar 2011, 2014-2015
*
* 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
@@ -36,11 +36,16 @@
#include "local.h"
#include "localp.h"
#include "memory.h"
#include "smooth.h"
#include "util.h"
#include "logging.h"
/* ================================================== */
/* Maximum allowed frequency offset in ppm, the time must not stop
or run backwards */
#define MAX_FREQ 500000.0
/* Variable to store the current frequency, in ppm */
static double current_freq_ppm;
@@ -56,6 +61,7 @@ static lcl_AccrueOffsetDriver drv_accrue_offset;
static lcl_ApplyStepOffsetDriver drv_apply_step_offset;
static lcl_OffsetCorrectionDriver drv_offset_convert;
static lcl_SetLeapDriver drv_set_leap;
static lcl_SetSyncStatusDriver drv_set_sync_status;
/* ================================================== */
@@ -168,6 +174,13 @@ LCL_Initialise(void)
void
LCL_Finalise(void)
{
while (change_list.next != &change_list)
LCL_RemoveParameterChangeHandler(change_list.next->handler,
change_list.next->anything);
while (dispersion_notify_list.next != &dispersion_notify_list)
LCL_RemoveDispersionNotifyHandler(dispersion_notify_list.next->handler,
dispersion_notify_list.next->anything);
}
/* ================================================== */
@@ -247,7 +260,7 @@ void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *
ptr->next->prev = ptr->prev;
ptr->prev->next = ptr->next;
free(ptr);
Free(ptr);
}
/* ================================================== */
@@ -324,7 +337,7 @@ void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void
ptr->next->prev = ptr->prev;
ptr->prev->next = ptr->next;
free(ptr);
Free(ptr);
}
/* ================================================== */
@@ -389,6 +402,33 @@ LCL_ReadAbsoluteFrequency(void)
}
/* ================================================== */
static double
clamp_freq(double freq)
{
if (freq <= MAX_FREQ && freq >= -MAX_FREQ)
return freq;
LOG(LOGS_WARN, LOGF_Local, "Frequency %.1f ppm exceeds allowed maximum", freq);
return freq >= MAX_FREQ ? MAX_FREQ : -MAX_FREQ;
}
/* ================================================== */
static int
check_offset(struct timeval *now, double offset)
{
/* Check if the time will be still sane with accumulated offset */
if (UTI_IsTimeOffsetSane(now, -offset))
return 1;
LOG(LOGS_WARN, LOGF_Local, "Adjustment of %.1f seconds is invalid", -offset);
return 0;
}
/* ================================================== */
/* This involves both setting the absolute frequency with the
system-specific driver, as well as calling all notify handlers */
@@ -398,6 +438,8 @@ LCL_SetAbsoluteFrequency(double afreq_ppm)
struct timeval raw, cooked;
double dfreq;
afreq_ppm = clamp_freq(afreq_ppm);
/* Apply temperature compensation */
if (temp_comp_ppm != 0.0) {
afreq_ppm = afreq_ppm * (1.0 - 1.0e-6 * temp_comp_ppm) - temp_comp_ppm;
@@ -435,6 +477,8 @@ LCL_AccumulateDeltaFrequency(double dfreq)
current_freq_ppm += dfreq * (1.0e6 - current_freq_ppm);
current_freq_ppm = clamp_freq(current_freq_ppm);
/* Call the system-specific driver for setting the frequency */
current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 - old_freq_ppm);
@@ -459,6 +503,9 @@ LCL_AccumulateOffset(double offset, double corr_rate)
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&cooked, offset))
return;
(*drv_accrue_offset)(offset, corr_rate);
/* Dispatch to all handlers */
@@ -467,7 +514,7 @@ LCL_AccumulateOffset(double offset, double corr_rate)
/* ================================================== */
void
int
LCL_ApplyStepOffset(double offset)
{
struct timeval raw, cooked;
@@ -478,10 +525,21 @@ LCL_ApplyStepOffset(double offset)
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
(*drv_apply_step_offset)(offset);
if (!check_offset(&raw, offset))
return 0;
if (!(*drv_apply_step_offset)(offset)) {
LOG(LOGS_ERR, LOGF_Local, "Could not step clock");
return 0;
}
/* Reset smoothing on all clock steps */
SMT_Reset(&cooked);
/* Dispatch to all handlers */
invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeStep);
return 1;
}
/* ================================================== */
@@ -498,6 +556,23 @@ LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
/* ================================================== */
void
LCL_NotifyLeap(int leap)
{
struct timeval raw, cooked;
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
/* Smooth the leap second out */
SMT_Leap(&cooked, leap);
/* Dispatch to all handlers as if the clock was stepped */
invoke_parameter_change_handlers(&raw, &cooked, 0.0, -leap, LCL_ChangeStep);
}
/* ================================================== */
void
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
{
@@ -509,6 +584,9 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
to the change we are about to make */
LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&cooked, doffset))
return;
old_freq_ppm = current_freq_ppm;
/* Work out new absolute frequency. Note that absolute frequencies
@@ -516,6 +594,8 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
terms of the gradient of the (offset) v (local time) function. */
current_freq_ppm += dfreq * (1.0e6 - current_freq_ppm);
current_freq_ppm = clamp_freq(current_freq_ppm);
DEBUG_LOG(LOGF_Local, "old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
old_freq_ppm, current_freq_ppm, doffset);
@@ -550,7 +630,8 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert,
lcl_SetLeapDriver set_leap)
lcl_SetLeapDriver set_leap,
lcl_SetSyncStatusDriver set_sync_status)
{
drv_read_freq = read_freq;
drv_set_freq = set_freq;
@@ -558,6 +639,7 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
drv_apply_step_offset = apply_step_offset;
drv_offset_convert = offset_convert;
drv_set_leap = set_leap;
drv_set_sync_status = set_sync_status;
current_freq_ppm = (*drv_read_freq)();
@@ -577,9 +659,13 @@ LCL_MakeStep(void)
LCL_ReadRawTime(&raw);
LCL_GetOffsetCorrection(&raw, &correction, NULL);
if (!check_offset(&raw, -correction))
return 0;
/* Cancel remaining slew and make the step */
LCL_AccumulateOffset(correction, 0.0);
LCL_ApplyStepOffset(-correction);
if (!LCL_ApplyStepOffset(-correction))
return 0;
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.6f seconds", correction);
@@ -588,8 +674,16 @@ LCL_MakeStep(void)
/* ================================================== */
int
LCL_CanSystemLeap(void)
{
return drv_set_leap ? 1 : 0;
}
/* ================================================== */
void
LCL_SetLeap(int leap)
LCL_SetSystemLeap(int leap)
{
if (drv_set_leap) {
(drv_set_leap)(leap);
@@ -625,3 +719,13 @@ LCL_SetTempComp(double comp)
}
/* ================================================== */
void
LCL_SetSyncStatus(int synchronised, double est_error, double max_error)
{
if (drv_set_sync_status) {
(drv_set_sync_status)(synchronised, est_error, max_error);
}
}
/* ================================================== */

22
local.h
View File

@@ -159,13 +159,17 @@ extern void LCL_AccumulateOffset(double offset, double corr_rate);
the system clock is fast on true time, i.e. it needs to be stepped
backwards. (Same convention as for AccumulateOffset routine). */
extern void LCL_ApplyStepOffset(double offset);
extern int 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);
/* Routine to invoke notify handlers on leap second when the system clock
doesn't correct itself */
extern void LCL_NotifyLeap(int leap);
/* Perform the combination of modifying the frequency and applying
a slew, in one easy step */
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
@@ -194,10 +198,14 @@ extern void LCL_Finalise(void);
to a timezone problem. */
extern int LCL_MakeStep(void);
/* Routine to schedule a leap second. Leap second will be inserted
at the end of the day if argument is positive, deleted if negative,
and zero cancels scheduled leap second. */
extern void LCL_SetLeap(int leap);
/* Check if the system driver supports leap seconds, i.e. LCL_SetSystemLeap
does something */
extern int LCL_CanSystemLeap(void);
/* Routine to set the system clock to correct itself for a leap second if
supported. Leap second will be inserted at the end of the day if the
argument is positive, deleted if negative, and zero resets the setting. */
extern void LCL_SetSystemLeap(int leap);
/* Routine to set a frequency correction (in ppm) that should be applied
to local clock to compensate for temperature changes. A positive
@@ -206,4 +214,8 @@ extern void LCL_SetLeap(int leap);
due to clamping or rounding). */
extern double LCL_SetTempComp(double comp);
/* Routine to update the synchronisation status in the kernel to allow other
applications to know if the system clock is synchronised and error bounds */
extern void LCL_SetSyncStatus(int synchronised, double est_error, double max_error);
#endif /* GOT_LOCAL_H */

View File

@@ -47,7 +47,7 @@ typedef void (*lcl_AccrueOffsetDriver)(double offset, double corr_rate);
/* System driver to apply a step offset. A positive argument means step
the clock forwards. */
typedef void (*lcl_ApplyStepOffsetDriver)(double offset);
typedef int (*lcl_ApplyStepOffsetDriver)(double offset);
/* System driver to convert a raw time to an adjusted (cooked) time.
The number of seconds returned in 'corr' have to be added to the
@@ -57,6 +57,9 @@ typedef void (*lcl_OffsetCorrectionDriver)(struct timeval *raw, double *corr, do
/* System driver to schedule leap second */
typedef void (*lcl_SetLeapDriver)(int leap);
/* System driver to set the synchronisation status */
typedef void (*lcl_SetSyncStatusDriver)(int synchronised, double est_error, double max_error);
extern void lcl_InvokeDispersionNotifyHandlers(double dispersion);
extern void
@@ -65,6 +68,7 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert,
lcl_SetLeapDriver set_leap);
lcl_SetLeapDriver set_leap,
lcl_SetSyncStatusDriver set_sync_status);
#endif /* GOT_LOCALP_H */

View File

@@ -211,8 +211,6 @@ void LOG_SetDebugLevel(int level)
{
debug_level = level;
if (level >= DEBUG_LEVEL_PRINT_DEBUG) {
if (!DEBUG)
LOG(LOGS_WARN, LOGF_Logging, "Not compiled with full debugging support");
log_debug_enabled = 1;
}
}

View File

@@ -80,6 +80,7 @@ typedef enum {
LOGF_Local,
LOGF_Util,
LOGF_Main,
LOGF_Memory,
LOGF_ClientLog,
LOGF_Configure,
LOGF_CmdMon,
@@ -93,13 +94,15 @@ typedef enum {
LOGF_Sys,
LOGF_SysGeneric,
LOGF_SysLinux,
LOGF_SysMacOSX,
LOGF_SysNetBSD,
LOGF_SysSolaris,
LOGF_SysSunOS,
LOGF_SysWinnt,
LOGF_TempComp,
LOGF_RtcLinux,
LOGF_Refclock
LOGF_Refclock,
LOGF_Smooth,
} LOG_Facility;
/* Init function */

38
main.c
View File

@@ -48,8 +48,8 @@
#include "rtc.h"
#include "refclock.h"
#include "clientlog.h"
#include "broadcast.h"
#include "nameserv.h"
#include "smooth.h"
#include "tempcomp.h"
/* ================================================== */
@@ -86,28 +86,34 @@ MAI_CleanupAndExit(void)
SRC_DumpSources();
}
/* Don't update clock when removing sources */
REF_SetMode(REF_ModeIgnore);
SMT_Finalise();
TMC_Finalise();
MNL_Finalise();
CLG_Finalise();
NSR_Finalise();
NCR_Finalise();
BRD_Finalise();
CAM_Finalise();
NIO_Finalise();
SST_Finalise();
REF_Finalise();
KEY_Finalise();
RCL_Finalise();
SRC_Finalise();
REF_Finalise();
RTC_Finalise();
CAM_Finalise();
NIO_Finalise();
SYS_Finalise();
SCH_Finalise();
LCL_Finalise();
delete_pidfile();
CNF_Finalise();
LOG_Finalise();
HSH_Finalise();
exit(exit_status);
}
@@ -341,6 +347,7 @@ int main
(int argc, char **argv)
{
const char *conf_file = DEFAULT_CONF_FILE;
const char *progname = argv[0];
char *user = NULL;
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
int do_init_rtc = 0, restarted = 0;
@@ -379,8 +386,8 @@ 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", CHRONY_VERSION);
exit(0);
printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
return 0;
} else if (!strcmp("-n", *argv)) {
nofork = 1;
} else if (!strcmp("-d", *argv)) {
@@ -399,6 +406,10 @@ int main
address_family = IPADDR_INET4;
} else if (!strcmp("-6", *argv)) {
address_family = IPADDR_INET6;
} else if (!strcmp("-h", *argv) || !strcmp("--help", *argv)) {
printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-f FILE|COMMAND...]\n",
progname);
return 0;
} else if (*argv[0] == '-') {
LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
} else {
@@ -411,7 +422,7 @@ int main
if (getuid() != 0) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
fprintf(stderr,"Not superuser\n");
exit(1);
return 1;
}
/* Turn into a daemon */
@@ -425,11 +436,12 @@ int main
LOG_SetDebugLevel(debug);
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting", CHRONY_VERSION);
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting (%s)",
CHRONY_VERSION, CHRONYD_FEATURES);
DNS_SetAddressFamily(address_family);
CNF_SetRestarted(restarted);
CNF_Initialise(restarted);
/* Parse the config file or the remaining command line arguments */
if (!config_args) {
@@ -455,8 +467,6 @@ int main
LCL_Initialise();
SCH_Initialise();
SYS_Initialise();
NIO_Initialise(address_family);
CAM_Initialise(address_family);
RTC_Initialise(do_init_rtc);
SRC_Initialise();
RCL_Initialise();
@@ -485,12 +495,14 @@ int main
REF_Initialise();
SST_Initialise();
BRD_Initialise();
NIO_Initialise(address_family);
CAM_Initialise(address_family);
NCR_Initialise();
NSR_Initialise();
CLG_Initialise();
MNL_Initialise();
TMC_Initialise();
SMT_Initialise();
/* From now on, it is safe to do finalisation on exit */
initialised = 1;

View File

@@ -39,7 +39,7 @@ echo $version > version.txt
sed -i -e "s%@@VERSION@@%${version}%" examples/chrony.spec
for m in chrony.1 chronyc.1.in chrony.conf.5.in chronyd.8.in; do
for m 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
@@ -59,15 +59,9 @@ if [ $(wc -l < INSTALL) -gt 100 -o $(wc -l < INSTALL) -lt 85 ]; then
exit 3
fi
awk '/^[1-9] Frequently asked questions$/{p=1}
/^Appendix A GNU General Public License$/{exit}; p' chrony.txt | \
tail -n +4 | sed 's/^[1-9]\.\([1-9]\)/\1/' | sed 's/^----/--/' | \
sed 's/^====/==/' > FAQ
if [ $(wc -l < FAQ) -gt 400 -o $(wc -l < FAQ) -lt 200 ]; then
echo "FAQ generated incorrectly?"
exit 3
fi
a2x --lynx -f text doc/faq.adoc || exit 1
mv doc/faq.text FAQ
rm -rf doc
rm -f config.h config.log make_release .gitignore

View File

@@ -54,6 +54,8 @@ typedef struct {
(measured-predicted)) */
} Sample;
#define MIN_SAMPLE_SEPARATION 1.0
#define MAX_SAMPLES 16
static Sample samples[16];
@@ -174,14 +176,24 @@ int
MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
{
struct timeval now;
double offset;
double offset, diff;
int i;
if (enabled) {
/* Check whether timestamp is within margin of old one */
LCL_ReadCookedTime(&now, NULL);
/* Make sure the provided timestamp is sane and the sample
is not too close to the last one */
if (!UTI_IsTimeOffsetSane(ts, 0.0))
return 0;
if (n_samples) {
UTI_DiffTimevalsToDouble(&diff, &now, &samples[n_samples - 1].when);
if (diff < MIN_SAMPLE_SEPARATION)
return 0;
}
UTI_DiffTimevalsToDouble(&offset, &now, ts);
/* Check if buffer full up */
@@ -258,6 +270,14 @@ MNL_Reset(void)
n_samples = 0;
}
/* ================================================== */
int
MNL_IsEnabled(void)
{
return enabled;
}
/* ================================================== */
/* Generate report data for the REQ_MANUAL_LIST command/monitoring
protocol */

View File

@@ -38,6 +38,7 @@ extern int MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfre
extern void MNL_Enable(void);
extern void MNL_Disable(void);
extern void MNL_Reset(void);
extern int MNL_IsEnabled(void);
extern void MNL_ReportSamples(RPT_ManualSamplesReport *report, int max, int *n);
extern int MNL_DeleteSample(int index);

67
memory.c Normal file
View File

@@ -0,0 +1,67 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014
*
* 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.
*
**********************************************************************
=======================================================================
Utility functions for memory allocation.
*/
#include "config.h"
#include "logging.h"
#include "memory.h"
void *
Malloc(size_t size)
{
void *r;
r = malloc(size);
if (!r && size)
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
return r;
}
void *
Realloc(void *ptr, size_t size)
{
void *r;
r = realloc(ptr, size);
if (!r && size)
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
return r;
}
char *
Strdup(const char *s)
{
void *r;
r = strdup(s);
if (!r)
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
return r;
}

View File

@@ -27,11 +27,15 @@
#ifndef GOT_MEMORY_H
#define GOT_MEMORY_H
#define Malloc(x) malloc(x)
#define MallocNew(T) ((T *) malloc(sizeof(T)))
#define MallocArray(T, n) ((T *) malloc((n) * sizeof(T)))
#define Realloc(x,y) realloc(x,y)
#define ReallocArray(T,n,x) ((T *) realloc((void *)(x), (n)*sizeof(T)))
/* Wrappers checking for errors */
extern void *Malloc(size_t size);
extern void *Realloc(void *ptr, size_t size);
extern char *Strdup(const char *s);
/* Convenient macros */
#define MallocNew(T) ((T *) Malloc(sizeof(T)))
#define MallocArray(T, n) ((T *) Malloc((n) * sizeof(T)))
#define ReallocArray(T,n,x) ((T *) Realloc((void *)(x), (n)*sizeof(T)))
#define Free(x) free(x)
#endif /* GOT_MEMORY_H */

View File

@@ -30,6 +30,7 @@
#include "sysincl.h"
#include "memory.h"
#include "mkdirpp.h"
static int
@@ -74,7 +75,7 @@ mkdir_and_parents(const char *path)
int i, j, k, last;
len = strlen(path);
p = (char *) malloc(1 + len);
p = (char *)Malloc(1 + len);
i = k = 0;
while (1) {
@@ -84,7 +85,7 @@ mkdir_and_parents(const char *path)
p[i] = 0;
if (do_dir(p) < 0) {
free(p);
Free(p);
return 0;
}
@@ -114,7 +115,7 @@ mkdir_and_parents(const char *path)
}
free(p);
Free(p);
return 1;
}

View File

@@ -44,11 +44,11 @@ DNS_SetAddressFamily(int family)
}
DNS_Status
DNS_Name2IPAddress(const char *name, IPAddr *addr)
DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
{
#ifdef HAVE_GETADDRINFO
struct addrinfo hints, *res, *ai;
int result;
int i, result;
memset(&hints, 0, sizeof (hints));
hints.ai_family = AF_UNSPEC;
@@ -64,38 +64,58 @@ DNS_Name2IPAddress(const char *name, IPAddr *addr)
#endif
}
for (ai = res; !result && ai != NULL; ai = ai->ai_next) {
for (ai = res, i = 0; i < max_addrs && ai != NULL; ai = ai->ai_next) {
switch (ai->ai_family) {
case AF_INET:
addr->family = IPADDR_INET4;
addr->addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr);
result = 1;
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4)
continue;
ip_addrs[i].family = IPADDR_INET4;
ip_addrs[i].addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr);
i++;
break;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
case AF_INET6:
addr->family = IPADDR_INET6;
memcpy(&addr->addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr, sizeof (addr->addr.in6));
result = 1;
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET6)
continue;
ip_addrs[i].family = IPADDR_INET6;
memcpy(&ip_addrs[i].addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr,
sizeof (ip_addrs->addr.in6));
i++;
break;
#endif
}
if (result && address_family != IPADDR_UNSPEC && address_family != addr->family)
result = 0;
}
for (; i < max_addrs; i++)
ip_addrs[i].family = IPADDR_UNSPEC;
freeaddrinfo(res);
return result ? DNS_Success : DNS_Failure;
return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure;
#else
struct hostent *host;
int i;
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4)
return DNS_Failure;
host = gethostbyname(name);
if (host == NULL) {
if (h_errno == TRY_AGAIN)
return DNS_TryAgain;
} else {
addr->family = IPADDR_INET4;
addr->addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[0]);
if (host->h_addrtype != AF_INET || !host->h_addr_list[0])
return DNS_Failure;
for (i = 0; host->h_addr_list[i] && i < max_addrs; i++) {
ip_addrs[i].family = IPADDR_INET4;
ip_addrs[i].addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[i]);
}
for (; i < max_addrs; i++)
ip_addrs[i].family = IPADDR_UNSPEC;
return DNS_Success;
}
@@ -115,33 +135,14 @@ DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
{
char *result = NULL;
#ifdef HAVE_IPV6
struct sockaddr_in in4;
#ifdef FEAT_IPV6
struct sockaddr_in6 in6;
socklen_t slen;
char hbuf[NI_MAXHOST];
switch (ip_addr->family) {
case IPADDR_INET4:
memset(&in4, 0, sizeof (in4));
#ifdef SIN6_LEN
in4.sin_len = sizeof (in4);
#endif
in4.sin_family = AF_INET;
in4.sin_addr.s_addr = htonl(ip_addr->addr.in4);
if (!getnameinfo((const struct sockaddr *)&in4, sizeof (in4), hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
break;
case IPADDR_INET6:
memset(&in6, 0, sizeof (in6));
#ifdef SIN6_LEN
in6.sin6_len = sizeof (in6);
#endif
in6.sin6_family = AF_INET6;
memcpy(&in6.sin6_addr.s6_addr, ip_addr->addr.in6, sizeof (in6.sin6_addr.s6_addr));
if (!getnameinfo((const struct sockaddr *)&in6, sizeof (in6), hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
break;
}
slen = UTI_IPAndPortToSockaddr(ip_addr, 0, (struct sockaddr *)&in6);
if (!getnameinfo((struct sockaddr *)&in6, slen, hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
#else
struct hostent *host;
uint32_t addr;
@@ -151,7 +152,7 @@ DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
addr = htonl(ip_addr->addr.in4);
host = gethostbyaddr((const char *) &addr, sizeof (ip_addr), AF_INET);
break;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
case IPADDR_INET6:
host = gethostbyaddr((const void *) ip_addr->addr.in6, sizeof (ip_addr->addr.in6), AF_INET6);
break;

View File

@@ -39,7 +39,7 @@ typedef enum {
/* Resolve names only to selected address family */
extern void DNS_SetAddressFamily(int family);
extern DNS_Status DNS_Name2IPAddress(const char *name, IPAddr *addr);
extern DNS_Status DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs);
extern int DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len);

View File

@@ -34,17 +34,17 @@
#include "sched.h"
#include "util.h"
#ifdef FEAT_ASYNCDNS
#ifdef USE_PTHREAD_ASYNCDNS
#include <pthread.h>
#define MAX_ADDRESSES 16
/* ================================================== */
struct DNS_Async_Instance {
const char *name;
DNS_Status status;
IPAddr addr;
IPAddr addresses[MAX_ADDRESSES];
DNS_NameResolveHandler handler;
void *arg;
@@ -61,7 +61,7 @@ start_resolving(void *anything)
{
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
inst->status = DNS_Name2IPAddress(inst->name, &inst->addr);
inst->status = DNS_Name2IPAddress(inst->name, inst->addresses, MAX_ADDRESSES);
/* Notify the main thread that the result is ready */
if (write(inst->pipe[1], "", 1) < 0)
@@ -76,6 +76,7 @@ static void
end_resolving(void *anything)
{
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
int i;
if (pthread_join(inst->thread, NULL)) {
LOG_FATAL(LOGF_Nameserv, "pthread_join() failed");
@@ -87,7 +88,11 @@ end_resolving(void *anything)
close(inst->pipe[0]);
close(inst->pipe[1]);
(inst->handler)(inst->status, &inst->addr, inst->arg);
for (i = 0; inst->status == DNS_Success && i < MAX_ADDRESSES &&
inst->addresses[i].family != IPADDR_UNSPEC; i++)
;
(inst->handler)(inst->status, i, inst->addresses, inst->arg);
Free(inst);
}
@@ -124,21 +129,3 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
#else
#error
#endif
#else
/* This is a blocking implementation used when nothing else is available */
void
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
{
IPAddr addr;
DNS_Status status;
status = DNS_Name2IPAddress(name, &addr);
(handler)(status, &addr, anything);
}
/* ================================================== */
#endif

View File

@@ -31,7 +31,7 @@
#include "nameserv.h"
/* Function type for callback to process the result */
typedef void (*DNS_NameResolveHandler)(DNS_Status status, IPAddr *ip_addr, void *anything);
typedef void (*DNS_NameResolveHandler)(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *anything);
/* Request resolving of a name to IP address. The handler will be
called when the result is available, but it may be also called

53
ntp.h
View File

@@ -38,7 +38,23 @@ typedef struct {
typedef uint32_t NTP_int32;
#define MAX_NTP_AUTH_DATA_LEN MAX_HASH_LENGTH
/* The NTP protocol version that we support */
#define NTP_VERSION 4
/* Maximum stratum number (infinity) */
#define NTP_MAX_STRATUM 16
/* The minimum valid length of an extension field */
#define NTP_MIN_EXTENSION_LENGTH 16
/* The maximum assumed length of all extension fields in received
packets (RFC 5905 doesn't specify a limit on length or number of
extension fields in one packet) */
#define NTP_MAX_EXTENSIONS_LENGTH 1024
/* The minimum and maximum supported length of MAC */
#define NTP_MIN_MAC_LENGTH 16
#define NTP_MAX_MAC_LENGTH MAX_HASH_LENGTH
/* Type definition for leap bits */
typedef enum {
@@ -69,24 +85,33 @@ typedef struct {
NTP_int64 originate_ts;
NTP_int64 receive_ts;
NTP_int64 transmit_ts;
/* Optional extension fields, we don't send packets with them yet */
/* uint8_t extensions[] */
/* Optional message authentication code (MAC) */
NTP_int32 auth_keyid;
uint8_t auth_data[MAX_NTP_AUTH_DATA_LEN];
uint8_t auth_data[NTP_MAX_MAC_LENGTH];
} NTP_Packet;
/* We have to declare a buffer type to hold a datagram read from the
network. Even though we won't be using them (yet?!), this must be
large enough to hold NTP control messages. */
#define NTP_NORMAL_PACKET_LENGTH (int)offsetof(NTP_Packet, auth_keyid)
/* Define the maximum number of bytes that can be read in a single
message. (This is cribbed from ntp.h in the xntpd source code). */
#define MAX_NTP_MESSAGE_SIZE (468+12+16+4)
typedef union {
/* The buffer used to hold a datagram read from the network */
typedef struct {
NTP_Packet ntp_pkt;
uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
} ReceiveBuffer;
uint8_t extensions[NTP_MAX_EXTENSIONS_LENGTH];
} NTP_Receive_Buffer;
#define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
/* Macros to work with the lvm field */
#define NTP_LVM_TO_LEAP(lvm) (((lvm) >> 6) & 0x3)
#define NTP_LVM_TO_VERSION(lvm) (((lvm) >> 3) & 0x7)
#define NTP_LVM_TO_MODE(lvm) ((lvm) & 0x7)
#define NTP_LVM(leap, version, mode) \
((((leap) << 6) & 0xc0) | (((version) << 3) & 0x38) | ((mode) & 0x07))
/* Special NTP reference IDs */
#define NTP_REFID_UNSYNC 0x0UL
#define NTP_REFID_LOCAL 0x7F7F0101UL /* 127.127.1.1 */
#define NTP_REFID_SMOOTH 0x7F7F01FFUL /* 127.127.1.255 */
#endif /* GOT_NTP_H */

1153
ntp_core.c

File diff suppressed because it is too large Load Diff

View File

@@ -58,9 +58,12 @@ extern void NCR_StartInstance(NCR_Instance instance);
/* Reset an instance */
extern void NCR_ResetInstance(NCR_Instance inst);
/* Change the remote address of an instance */
extern void NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr);
/* 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_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, int sock_fd, int length);
extern int NCR_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, NTP_Local_Address *local_addr, int length);
/* This routine is called when a new packet arrives off the network,
and we do not recognize its source */
@@ -104,4 +107,6 @@ extern NTP_Remote_Address *NCR_GetRemoteAddress(NCR_Instance instance);
extern int NCR_IsSyncPeer(NCR_Instance instance);
extern void NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval);
#endif /* GOT_NTP_CORE_H */

229
ntp_io.c
View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Timo Teras 2009
* Copyright (C) Miroslav Lichvar 2009, 2013-2014
* Copyright (C) Miroslav Lichvar 2009, 2013-2015
*
* 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
@@ -43,7 +43,7 @@
union sockaddr_in46 {
struct sockaddr_in in4;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
struct sockaddr_in6 in6;
#endif
struct sockaddr u;
@@ -52,15 +52,27 @@ union sockaddr_in46 {
/* The server/peer and client sockets for IPv4 and IPv6 */
static int server_sock_fd4;
static int client_sock_fd4;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
static int server_sock_fd6;
static int client_sock_fd6;
#endif
/* Reference counters for server sockets to keep them open only when needed */
static int server_sock_ref4;
#ifdef FEAT_IPV6
static int server_sock_ref6;
#endif
/* Flag indicating we create a new connected client socket for each
server instead of sharing client_sock_fd4 and client_sock_fd6 */
static int separate_client_sockets;
/* Flag indicating the server sockets are not created dynamically when needed,
either to have a socket for client requests when separate client sockets
are disabled and client port is equal to server port, or the server port is
disabled */
static int permanent_server_sockets;
/* Flag indicating that we have been initialised */
static int initialised=0;
@@ -85,8 +97,13 @@ prepare_socket(int family, int port_number, int client_only)
sock_fd = socket(family, SOCK_DGRAM, 0);
if (sock_fd < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
if (!client_only) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
} else {
DEBUG_LOG(LOGF_NtpIO, "Could not open %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
}
return INVALID_SOCK_FD;
}
@@ -116,7 +133,7 @@ prepare_socket(int family, int port_number, int client_only)
my_addr_len = sizeof (my_addr.in4);
break;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
case AF_INET6:
if (!client_only)
CNF_GetBindAddress(IPADDR_INET6, &bind_address);
@@ -174,14 +191,13 @@ prepare_socket(int family, int port_number, int client_only)
if (family == AF_INET) {
#ifdef IP_PKTINFO
/* We want the local IP info on server sockets */
if (!client_only &&
setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
if (setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set packet info socket option");
/* Don't quit - we might survive anyway */
}
#endif
}
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
else if (family == AF_INET6) {
#ifdef IPV6_V6ONLY
/* Receive IPv6 packets only */
@@ -190,17 +206,15 @@ prepare_socket(int family, int port_number, int client_only)
}
#endif
if (!client_only) {
#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 set 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 set IPv6 packet info socket option");
}
#endif
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set 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 set IPv6 packet info socket option");
}
#endif
}
#endif
@@ -226,7 +240,7 @@ prepare_separate_client_socket(int family)
switch (family) {
case IPADDR_INET4:
return prepare_socket(AF_INET, 0, 1);
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
case IPADDR_INET6:
return prepare_socket(AF_INET6, 0, 1);
#endif
@@ -243,27 +257,9 @@ connect_socket(int sock_fd, NTP_Remote_Address *remote_addr)
union sockaddr_in46 addr;
socklen_t addr_len;
memset(&addr, 0, sizeof (addr));
addr_len = UTI_IPAndPortToSockaddr(&remote_addr->ip_addr, remote_addr->port, &addr.u);
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
addr_len = sizeof (addr.in4);
addr.in4.sin_family = AF_INET;
addr.in4.sin_addr.s_addr = htonl(remote_addr->ip_addr.addr.in4);
addr.in4.sin_port = htons(remote_addr->port);
break;
#ifdef HAVE_IPV6
case IPADDR_INET6:
addr_len = sizeof (addr.in6);
addr.in6.sin6_family = AF_INET6;
memcpy(addr.in6.sin6_addr.s6_addr, remote_addr->ip_addr.addr.in6,
sizeof (addr.in6.sin6_addr.s6_addr));
addr.in6.sin6_port = htons(remote_addr->port);
break;
#endif
default:
assert(0);
}
assert(addr_len);
if (connect(sock_fd, &addr.u, addr_len) < 0) {
DEBUG_LOG(LOGF_NtpIO, "Could not connect NTP socket to %s:%d : %s",
@@ -304,15 +300,20 @@ NIO_Initialise(int family)
if (client_port < 0)
client_port = 0;
permanent_server_sockets = !server_port || (!separate_client_sockets &&
client_port == server_port);
server_sock_fd4 = INVALID_SOCK_FD;
client_sock_fd4 = INVALID_SOCK_FD;
#ifdef HAVE_IPV6
server_sock_ref4 = 0;
#ifdef FEAT_IPV6
server_sock_fd6 = INVALID_SOCK_FD;
client_sock_fd6 = INVALID_SOCK_FD;
server_sock_ref6 = 0;
#endif
if (family == IPADDR_UNSPEC || family == IPADDR_INET4) {
if (server_port)
if (permanent_server_sockets && server_port)
server_sock_fd4 = prepare_socket(AF_INET, server_port, 0);
if (!separate_client_sockets) {
if (client_port != server_port || !server_port)
@@ -321,9 +322,9 @@ NIO_Initialise(int family)
client_sock_fd4 = server_sock_fd4;
}
}
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
if (family == IPADDR_UNSPEC || family == IPADDR_INET6) {
if (server_port)
if (permanent_server_sockets && server_port)
server_sock_fd6 = prepare_socket(AF_INET6, server_port, 0);
if (!separate_client_sockets) {
if (client_port != server_port || !server_port)
@@ -334,12 +335,13 @@ NIO_Initialise(int family)
}
#endif
if ((server_port && server_sock_fd4 == INVALID_SOCK_FD
#ifdef HAVE_IPV6
if ((server_port && server_sock_fd4 == INVALID_SOCK_FD &&
permanent_server_sockets
#ifdef FEAT_IPV6
&& server_sock_fd6 == INVALID_SOCK_FD
#endif
) || (!separate_client_sockets && client_sock_fd4 == INVALID_SOCK_FD
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
&& client_sock_fd6 == INVALID_SOCK_FD
#endif
)) {
@@ -356,7 +358,7 @@ NIO_Finalise(void)
close_socket(client_sock_fd4);
close_socket(server_sock_fd4);
server_sock_fd4 = client_sock_fd4 = INVALID_SOCK_FD;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
if (server_sock_fd6 != client_sock_fd6)
close_socket(client_sock_fd6);
close_socket(server_sock_fd6);
@@ -368,7 +370,7 @@ NIO_Finalise(void)
/* ================================================== */
int
NIO_GetClientSocket(NTP_Remote_Address *remote_addr)
NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
{
if (separate_client_sockets) {
int sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family);
@@ -386,7 +388,7 @@ NIO_GetClientSocket(NTP_Remote_Address *remote_addr)
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
return client_sock_fd4;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
case IPADDR_INET6:
return client_sock_fd6;
#endif
@@ -399,13 +401,25 @@ NIO_GetClientSocket(NTP_Remote_Address *remote_addr)
/* ================================================== */
int
NIO_GetServerSocket(NTP_Remote_Address *remote_addr)
NIO_OpenServerSocket(NTP_Remote_Address *remote_addr)
{
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
if (permanent_server_sockets)
return server_sock_fd4;
if (server_sock_fd4 == INVALID_SOCK_FD)
server_sock_fd4 = prepare_socket(AF_INET, CNF_GetNTPPort(), 0);
if (server_sock_fd4 != INVALID_SOCK_FD)
server_sock_ref4++;
return server_sock_fd4;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
case IPADDR_INET6:
if (permanent_server_sockets)
return server_sock_fd6;
if (server_sock_fd6 == INVALID_SOCK_FD)
server_sock_fd6 = prepare_socket(AF_INET6, CNF_GetNTPPort(), 0);
if (server_sock_fd6 != INVALID_SOCK_FD)
server_sock_ref6++;
return server_sock_fd6;
#endif
default:
@@ -424,12 +438,39 @@ NIO_CloseClientSocket(int sock_fd)
/* ================================================== */
void
NIO_CloseServerSocket(int sock_fd)
{
if (permanent_server_sockets || sock_fd == INVALID_SOCK_FD)
return;
if (sock_fd == server_sock_fd4) {
if (--server_sock_ref4 <= 0) {
close_socket(server_sock_fd4);
server_sock_fd4 = INVALID_SOCK_FD;
}
}
#ifdef FEAT_IPV6
else if (sock_fd == server_sock_fd6) {
if (--server_sock_ref6 <= 0) {
close_socket(server_sock_fd6);
server_sock_fd6 = INVALID_SOCK_FD;
}
}
#endif
else {
assert(0);
}
}
/* ================================================== */
int
NIO_IsServerSocket(int sock_fd)
{
return sock_fd != INVALID_SOCK_FD &&
(sock_fd == server_sock_fd4
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
|| sock_fd == server_sock_fd6
#endif
);
@@ -444,7 +485,7 @@ read_from_socket(void *anything)
to read, otherwise it will block. */
int status, sock_fd;
ReceiveBuffer message;
NTP_Receive_Buffer message;
union sockaddr_in46 where_from;
unsigned int flags = 0;
struct timeval now;
@@ -460,7 +501,7 @@ read_from_socket(void *anything)
SCH_GetLastEventTime(&now, &now_err, NULL);
iov.iov_base = message.arbitrary;
iov.iov_base = &message.ntp_pkt;
iov.iov_len = sizeof(message);
msg.msg_name = &where_from;
msg.msg_namelen = sizeof(where_from);
@@ -484,23 +525,7 @@ read_from_socket(void *anything)
if (msg.msg_namelen > sizeof (where_from))
LOG_FATAL(LOGF_NtpIO, "Truncated source address");
switch (where_from.u.sa_family) {
case AF_INET:
remote_addr.ip_addr.family = IPADDR_INET4;
remote_addr.ip_addr.addr.in4 = ntohl(where_from.in4.sin_addr.s_addr);
remote_addr.port = ntohs(where_from.in4.sin_port);
break;
#ifdef HAVE_IPV6
case AF_INET6:
remote_addr.ip_addr.family = IPADDR_INET6;
memcpy(&remote_addr.ip_addr.addr.in6, where_from.in6.sin6_addr.s6_addr,
sizeof (remote_addr.ip_addr.addr.in6));
remote_addr.port = ntohs(where_from.in6.sin6_port);
break;
#endif
default:
assert(0);
}
UTI_SockaddrToIPAndPort(&where_from.u, &remote_addr.ip_addr, &remote_addr.port);
local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.sock_fd = sock_fd;
@@ -537,14 +562,11 @@ read_from_socket(void *anything)
#endif
}
if (status > 0) {
DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd %d",
status,
UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd);
}
DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd %d",
status, UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd);
if (status >= NTP_NORMAL_PACKET_SIZE && status <= sizeof(NTP_Packet)) {
if (status >= NTP_NORMAL_PACKET_LENGTH) {
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err,
&remote_addr, &local_addr, status);
@@ -558,7 +580,7 @@ read_from_socket(void *anything)
}
/* ================================================== */
/* Send a packet to given address */
/* Send a packet to remote address from local address */
static int
send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
@@ -578,31 +600,15 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
return 0;
}
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
/* Don't set address with connected socket */
if (local_addr->sock_fd != server_sock_fd4 && separate_client_sockets)
break;
memset(&remote.in4, 0, sizeof (remote.in4));
addrlen = sizeof (remote.in4);
remote.in4.sin_family = AF_INET;
remote.in4.sin_port = htons(remote_addr->port);
remote.in4.sin_addr.s_addr = htonl(remote_addr->ip_addr.addr.in4);
break;
#ifdef HAVE_IPV6
case IPADDR_INET6:
/* Don't set address with connected socket */
if (local_addr->sock_fd != server_sock_fd6 && separate_client_sockets)
break;
memset(&remote.in6, 0, sizeof (remote.in6));
addrlen = sizeof (remote.in6);
remote.in6.sin6_family = AF_INET6;
remote.in6.sin6_port = htons(remote_addr->port);
memcpy(&remote.in6.sin6_addr.s6_addr, &remote_addr->ip_addr.addr.in6,
sizeof (remote.in6.sin6_addr.s6_addr));
break;
/* Don't set address with connected socket */
if (local_addr->sock_fd == server_sock_fd4 ||
#ifdef FEAT_IPV6
local_addr->sock_fd == server_sock_fd6 ||
#endif
default:
!separate_client_sockets) {
addrlen = UTI_IPAndPortToSockaddr(&remote_addr->ip_addr, remote_addr->port,
&remote.u);
if (!addrlen)
return 0;
}
@@ -673,7 +679,7 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
return 0;
}
DEBUG_LOG(LOGF_NtpIO, "Sent to %s:%d from %s fd %d",
DEBUG_LOG(LOGF_NtpIO, "Sent %d bytes to %s:%d from %s fd %d", packetlen,
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd);
@@ -681,19 +687,10 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
}
/* ================================================== */
/* Send an unauthenticated packet to a given address */
/* Send a packet to a given address */
int
NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length)
{
return send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE, remote_addr, local_addr);
}
/* ================================================== */
/* Send an authenticated packet to a given address */
int
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len)
{
return send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE + auth_len, remote_addr, local_addr);
return send_packet((void *) packet, length, remote_addr, local_addr);
}

View File

@@ -39,21 +39,21 @@ extern void NIO_Initialise(int family);
extern void NIO_Finalise(void);
/* Function to obtain a socket for sending client packets */
extern int NIO_GetClientSocket(NTP_Remote_Address *remote_addr);
extern int NIO_OpenClientSocket(NTP_Remote_Address *remote_addr);
/* Function to obtain a socket for sending server/peer packets */
extern int NIO_GetServerSocket(NTP_Remote_Address *remote_addr);
extern int NIO_OpenServerSocket(NTP_Remote_Address *remote_addr);
/* Function to close a socket returned by NIO_GetClientSocket() */
/* Function to close a socket returned by NIO_OpenClientSocket() */
extern void NIO_CloseClientSocket(int sock_fd);
/* Function to close a socket returned by NIO_OpenServerSocket() */
extern void NIO_CloseServerSocket(int sock_fd);
/* Function to check if socket is a server socket */
extern int NIO_IsServerSocket(int sock_fd);
/* Function to transmit a packet */
extern int NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr);
/* Function to transmit an authenticated packet */
extern int NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len);
extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);
#endif /* GOT_NTP_IO_H */

View File

@@ -31,6 +31,7 @@
#include "sysincl.h"
#include "array.h"
#include "ntp_sources.h"
#include "ntp_core.h"
#include "util.h"
@@ -48,20 +49,20 @@ typedef struct {
NTP_Remote_Address *remote_addr; /* The address of this source, non-NULL
means this slot in table is in use */
NCR_Instance data; /* Data for the protocol engine for this source */
char *name; /* Name of the source, may be NULL */
int pool; /* Number of the pool from which was this source
added or INVALID_POOL */
int tentative; /* Flag indicating there was no valid response
yet and the source may be removed if other
sources from the pool respond first */
} SourceRecord;
#define N_RECORDS 256
/* Fixed size table, because we use a hard coded hash algorithm. It
is rather unlikely we would have anything approaching this number
of sources. */
static SourceRecord records[N_RECORDS];
/* Hash table of SourceRecord, the size should be a power of two */
static ARR_Instance records;
/* Number of sources in the hash table */
static int n_sources;
/* The largest number of sources we want to have stored in the hash table */
#define MAX_SOURCES 64
/* Flag indicating new sources will be started automatically when added */
static int auto_start_sources = 0;
@@ -69,14 +70,23 @@ static int auto_start_sources = 0;
struct UnresolvedSource {
char *name;
int port;
NTP_Source_Type type;
SourceParameters params;
int replacement;
union {
struct {
NTP_Source_Type type;
SourceParameters params;
int pool;
int max_new_sources;
} new_source;
NTP_Remote_Address replace_source;
};
struct UnresolvedSource *next;
};
#define RESOLVE_INTERVAL_UNIT 7
#define MIN_RESOLVE_INTERVAL 2
#define MAX_RESOLVE_INTERVAL 9
#define MIN_REPLACEMENT_INTERVAL 8
static struct UnresolvedSource *unresolved_sources = NULL;
static int resolving_interval = 0;
@@ -84,10 +94,26 @@ static SCH_TimeoutID resolving_id;
static struct UnresolvedSource *resolving_source = NULL;
static NSR_SourceResolvingEndHandler resolving_end_handler = NULL;
#define MAX_POOL_SOURCES 16
#define INVALID_POOL (-1)
/* Pool of sources with the same name */
struct SourcePool {
/* Number of sources added from this pool (ignoring tentative sources) */
int sources;
/* Maximum number of sources */
int max_sources;
};
/* Array of SourcePool */
static ARR_Instance pools;
/* ================================================== */
/* Forward prototypes */
static void resolve_sources(void *arg);
static void rehash_records(void);
static void clean_source_record(SourceRecord *record);
static void
slew_sources(struct timeval *raw,
@@ -104,16 +130,25 @@ static int initialised = 0;
/* ================================================== */
static SourceRecord *
get_record(unsigned index)
{
return (SourceRecord *)ARR_GetElement(records, index);
}
/* ================================================== */
void
NSR_Initialise(void)
{
int i;
for (i=0; i<N_RECORDS; i++) {
records[i].remote_addr = NULL;
}
n_sources = 0;
initialised = 1;
records = ARR_CreateInstance(sizeof (SourceRecord));
rehash_records();
pools = ARR_CreateInstance(sizeof (struct SourcePool));
LCL_AddParameterChangeHandler(slew_sources, NULL);
}
@@ -122,6 +157,27 @@ NSR_Initialise(void)
void
NSR_Finalise(void)
{
SourceRecord *record;
struct UnresolvedSource *us;
unsigned int i;
ARR_DestroyInstance(pools);
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr)
clean_source_record(record);
}
ARR_DestroyInstance(records);
while (unresolved_sources) {
us = unresolved_sources;
unresolved_sources = us->next;
Free(us->name);
Free(us);
}
initialised = 0;
}
@@ -142,23 +198,24 @@ NSR_Finalise(void)
static void
find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
{
unsigned long hash;
unsigned long ip;
SourceRecord *record;
uint32_t hash;
unsigned int i, size;
unsigned short port;
uint8_t *ip6;
assert(N_RECORDS == 256);
size = ARR_GetSize(records);
switch (remote_addr->ip_addr.family) {
case IPADDR_INET6:
ip6 = remote_addr->ip_addr.addr.in6;
ip = (ip6[0] ^ ip6[4] ^ ip6[8] ^ ip6[12]) |
hash = (ip6[0] ^ ip6[4] ^ ip6[8] ^ ip6[12]) |
(ip6[1] ^ ip6[5] ^ ip6[9] ^ ip6[13]) << 8 |
(ip6[2] ^ ip6[6] ^ ip6[10] ^ ip6[14]) << 16 |
(ip6[3] ^ ip6[7] ^ ip6[11] ^ ip6[15]) << 24;
break;
case IPADDR_INET4:
ip = remote_addr->ip_addr.addr.in4;
hash = remote_addr->ip_addr.addr.in4;
break;
default:
*found = *slot = 0;
@@ -166,36 +223,77 @@ find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
}
port = remote_addr->port;
/* Compute hash value just by xor'ing the 4 bytes of the address together */
hash = ip ^ (ip >> 16);
hash = (hash ^ (hash >> 8)) & 0xff;
while (records[hash].remote_addr &&
UTI_CompareIPs(&records[hash].remote_addr->ip_addr,
&remote_addr->ip_addr, NULL)) {
hash++;
if (hash == 256) hash = 0;
}
for (i = 0; i < size / 2; i++) {
/* Use quadratic probing */
*slot = (hash + (i + i * i) / 2) % size;
record = get_record(*slot);
if (records[hash].remote_addr) {
if (records[hash].remote_addr->port == port) {
*found = 2;
} else {
*found = 1;
if (!record->remote_addr)
break;
if (!UTI_CompareIPs(&record->remote_addr->ip_addr,
&remote_addr->ip_addr, NULL)) {
*found = record->remote_addr->port == port ? 2 : 1;
return;
}
*slot = hash;
} else {
*found = 0;
*slot = hash;
}
*found = 0;
}
/* ================================================== */
/* Check if hash table of given size is sufficient to contain sources */
static int
check_hashtable_size(unsigned int sources, unsigned int size)
{
return sources * 2 + 1 < size;
}
/* ================================================== */
static void
rehash_records(void)
{
SourceRecord *temp_records;
unsigned int i, old_size, new_size;
int slot, found;
old_size = ARR_GetSize(records);
temp_records = MallocArray(SourceRecord, old_size);
memcpy(temp_records, ARR_GetElements(records), old_size * sizeof (SourceRecord));
/* The size of the hash table is always a power of two */
for (new_size = 4; !check_hashtable_size(n_sources, new_size); new_size *= 2)
;
ARR_SetSize(records, new_size);
for (i = 0; i < new_size; i++)
get_record(i)->remote_addr = NULL;
for (i = 0; i < old_size; i++) {
if (!temp_records[i].remote_addr)
continue;
find_slot(temp_records[i].remote_addr, &slot, &found);
assert(!found);
*get_record(slot) = temp_records[i];
}
Free(temp_records);
}
/* ================================================== */
/* Procedure to add a new source */
NSR_Status
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
static NSR_Status
add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, SourceParameters *params, int pool)
{
SourceRecord *record;
int slot, found;
assert(initialised);
@@ -205,17 +303,28 @@ NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParam
if (found) {
return NSR_AlreadyInUse;
} else {
if (n_sources == MAX_SOURCES) {
return NSR_TooManySources;
} else if (remote_addr->ip_addr.family != IPADDR_INET4 &&
if (remote_addr->ip_addr.family != IPADDR_INET4 &&
remote_addr->ip_addr.family != IPADDR_INET6) {
return NSR_InvalidAF;
} else {
n_sources++;
records[slot].data = NCR_GetInstance(remote_addr, type, params); /* Will need params passing through */
records[slot].remote_addr = NCR_GetRemoteAddress(records[slot].data);
if (!check_hashtable_size(n_sources, ARR_GetSize(records))) {
rehash_records();
find_slot(remote_addr, &slot, &found);
}
assert(!found);
record = get_record(slot);
record->data = NCR_GetInstance(remote_addr, type, params);
record->remote_addr = NCR_GetRemoteAddress(record->data);
record->name = name ? Strdup(name) : NULL;
record->pool = pool;
record->tentative = pool != INVALID_POOL ? 1 : 0;
if (auto_start_sources)
NCR_StartInstance(records[slot].data);
NCR_StartInstance(record->data);
return NSR_Success;
}
}
@@ -223,24 +332,80 @@ NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParam
/* ================================================== */
static NSR_Status
replace_source(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr)
{
int slot1, slot2, found;
SourceRecord *record;
find_slot(old_addr, &slot1, &found);
if (!found)
return NSR_NoSuchSource;
find_slot(new_addr, &slot2, &found);
if (found)
return NSR_AlreadyInUse;
record = get_record(slot1);
NCR_ChangeRemoteAddress(record->data, new_addr);
record->remote_addr = NCR_GetRemoteAddress(record->data);
/* The hash table must be rebuilt for the new address */
rehash_records();
LOG(LOGS_INFO, LOGF_NtpSources, "Source %s replaced with %s",
UTI_IPToString(&old_addr->ip_addr),
UTI_IPToString(&new_addr->ip_addr));
return NSR_Success;
}
/* ================================================== */
static void
name_resolve_handler(DNS_Status status, IPAddr *ip_addr, void *anything)
process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs)
{
NTP_Remote_Address address;
int i, added;
for (i = added = 0; i < n_addrs; i++) {
DEBUG_LOG(LOGF_NtpSources, "(%d) %s", i + 1, UTI_IPToString(&ip_addrs[i]));
address.ip_addr = ip_addrs[i];
address.port = us->port;
if (us->replacement) {
if (replace_source(&us->replace_source, &address) != NSR_AlreadyInUse)
break;
} else {
if (add_source(&address, us->name, us->new_source.type, &us->new_source.params,
us->new_source.pool) == NSR_Success)
added++;
if (added >= us->new_source.max_new_sources)
break;
}
}
}
/* ================================================== */
static void
name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *anything)
{
struct UnresolvedSource *us, **i, *next;
NTP_Remote_Address address;
us = (struct UnresolvedSource *)anything;
assert(us == resolving_source);
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %d addrs", us->name, n_addrs);
switch (status) {
case DNS_TryAgain:
break;
case DNS_Success:
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, UTI_IPToString(ip_addr));
address.ip_addr = *ip_addr;
address.port = us->port;
NSR_AddSource(&address, us->type, &us->params);
process_resolved_name(us, ip_addrs, n_addrs);
break;
case DNS_Failure:
LOG(LOGS_WARN, LOGF_NtpSources, "Invalid host %s", us->name);
@@ -251,8 +416,9 @@ name_resolve_handler(DNS_Status status, IPAddr *ip_addr, void *anything)
next = us->next;
if (status != DNS_TryAgain) {
/* Remove the source from the list */
/* Remove the source from the list on success or failure, replacements
are removed on any status */
if (us->replacement || status != DNS_TryAgain) {
for (i = &unresolved_sources; *i; i = &(*i)->next) {
if (*i == us) {
*i = us->next;
@@ -311,24 +477,61 @@ resolve_sources(void *arg)
/* ================================================== */
/* Procedure to add a new server or peer source, but instead of an IP address
only a name is provided */
void
NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params)
static void
append_unresolved_source(struct UnresolvedSource *us)
{
struct UnresolvedSource *us, **i;
us = MallocNew(struct UnresolvedSource);
us->name = name;
us->port = port;
us->type = type;
us->params = *params;
us->next = NULL;
struct UnresolvedSource **i;
for (i = &unresolved_sources; *i; i = &(*i)->next)
;
*i = us;
us->next = NULL;
}
/* ================================================== */
NSR_Status
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
{
return add_source(remote_addr, NULL, type, params, INVALID_POOL);
}
/* ================================================== */
void
NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params)
{
struct UnresolvedSource *us;
struct SourcePool *sp;
NTP_Remote_Address remote_addr;
/* If the name is an IP address, don't bother with full resolving now
or later when trying to replace the source */
if (UTI_StringToIP(name, &remote_addr.ip_addr)) {
remote_addr.port = port;
NSR_AddSource(&remote_addr, type, params);
return;
}
us = MallocNew(struct UnresolvedSource);
us->name = Strdup(name);
us->port = port;
us->replacement = 0;
us->new_source.type = type;
us->new_source.params = *params;
if (!pool) {
us->new_source.pool = INVALID_POOL;
us->new_source.max_new_sources = 1;
} else {
sp = (struct SourcePool *)ARR_GetNewElement(pools);
sp->sources = 0;
sp->max_sources = params->max_sources;
us->new_source.pool = ARR_GetSize(pools) - 1;
us->new_source.max_new_sources = MAX_POOL_SOURCES;
}
append_unresolved_source(us);
}
/* ================================================== */
@@ -365,12 +568,12 @@ NSR_ResolveSources(void)
void NSR_StartSources(void)
{
int i;
unsigned int i;
for (i = 0; i < N_RECORDS; i++) {
if (!records[i].remote_addr)
for (i = 0; i < ARR_GetSize(records); i++) {
if (!get_record(i)->remote_addr)
continue;
NCR_StartInstance(records[i].data);
NCR_StartInstance(get_record(i)->data);
}
}
@@ -383,6 +586,20 @@ void NSR_AutoStartSources(void)
/* ================================================== */
static void
clean_source_record(SourceRecord *record)
{
assert(record->remote_addr);
record->remote_addr = NULL;
NCR_DestroyInstance(record->data);
if (record->name)
Free(record->name);
n_sources--;
}
/* ================================================== */
/* 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
@@ -390,8 +607,7 @@ void NSR_AutoStartSources(void)
NSR_Status
NSR_RemoveSource(NTP_Remote_Address *remote_addr)
{
int i, slot, found;
SourceRecord temp_records[N_RECORDS];
int slot, found;
assert(initialised);
@@ -400,29 +616,12 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr)
return NSR_NoSuchSource;
}
n_sources--;
records[slot].remote_addr = NULL;
NCR_DestroyInstance(records[slot].data);
clean_source_record(get_record(slot));
/* Rehash the table to make sure there are no broken probe sequences.
This is costly, but it's not expected to happen frequently. */
memcpy(temp_records, records, sizeof (records));
for (i = 0; i < N_RECORDS; i++) {
records[i].remote_addr = NULL;
}
for (i = 0; i < N_RECORDS; i++) {
if (!temp_records[i].remote_addr)
continue;
find_slot(temp_records[i].remote_addr, &slot, &found);
assert(!found);
records[slot].remote_addr = temp_records[i].remote_addr;
records[slot].data = temp_records[i].data;
}
rehash_records();
return NSR_Success;
}
@@ -432,31 +631,134 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr)
void
NSR_RemoveAllSources(void)
{
int i;
SourceRecord *record;
unsigned int i;
for (i = 0; i < N_RECORDS; i++) {
if (!records[i].remote_addr)
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (!record->remote_addr)
continue;
NCR_DestroyInstance(records[i].data);
records[i].remote_addr = NULL;
clean_source_record(record);
}
rehash_records();
}
/* ================================================== */
static void
resolve_source_replacement(SourceRecord *record)
{
struct UnresolvedSource *us;
DEBUG_LOG(LOGF_NtpSources, "trying to replace %s",
UTI_IPToString(&record->remote_addr->ip_addr));
us = MallocNew(struct UnresolvedSource);
us->name = Strdup(record->name);
us->port = record->remote_addr->port;
us->replacement = 1;
us->replace_source = *record->remote_addr;
append_unresolved_source(us);
NSR_ResolveSources();
}
/* ================================================== */
void
NSR_HandleBadSource(IPAddr *address)
{
static struct timeval last_replacement;
struct timeval now;
NTP_Remote_Address remote_addr;
SourceRecord *record;
int slot, found;
double diff;
remote_addr.ip_addr = *address;
remote_addr.port = 0;
find_slot(&remote_addr, &slot, &found);
if (!found)
return;
record = get_record(slot);
/* Only sources with a name can be replaced */
if (!record->name)
return;
/* Don't resolve names too frequently */
SCH_GetLastEventTime(NULL, NULL, &now);
UTI_DiffTimevalsToDouble(&diff, &now, &last_replacement);
if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_REPLACEMENT_INTERVAL)) {
DEBUG_LOG(LOGF_NtpSources, "replacement postponed");
return;
}
last_replacement = now;
resolve_source_replacement(record);
}
/* ================================================== */
static void remove_tentative_pool_sources(int pool)
{
SourceRecord *record;
unsigned int i, removed;
for (i = removed = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (!record->remote_addr || record->pool != pool || !record->tentative)
continue;
DEBUG_LOG(LOGF_NtpSources, "removing tentative source %s",
UTI_IPToString(&record->remote_addr->ip_addr));
clean_source_record(record);
removed++;
}
if (removed)
rehash_records();
}
/* 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, NTP_Local_Address *local_addr, int length)
{
SourceRecord *record;
struct SourcePool *pool;
int slot, found;
assert(initialised);
find_slot(remote_addr, &slot, &found);
if (found == 2) { /* Must match IP address AND port number */
NCR_ProcessKnown(message, now, now_err, records[slot].data,
local_addr->sock_fd, length);
record = get_record(slot);
if (!NCR_ProcessKnown(message, now, now_err, record->data, local_addr, length))
return;
if (record->tentative) {
/* First reply from a pool source */
record->tentative = 0;
assert(record->pool != INVALID_POOL);
pool = (struct SourcePool *)ARR_GetElement(pools, record->pool);
pool->sources++;
DEBUG_LOG(LOGF_NtpSources, "pool %s has %d confirmed sources",
record->name, pool->sources);
/* If the number of sources reached the configured maximum, remove
the tentative sources added from this pool */
if (pool->sources >= pool->max_sources)
remove_tentative_pool_sources(record->pool);
}
} else {
NCR_ProcessUnknown(message, now, now_err, remote_addr, local_addr, length);
}
@@ -472,14 +774,16 @@ slew_sources(struct timeval *raw,
LCL_ChangeType change_type,
void *anything)
{
int i;
SourceRecord *record;
unsigned int i;
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr) {
if (change_type == LCL_ChangeUnknownStep) {
NCR_ResetInstance(records[i].data);
NCR_ResetInstance(record->data);
} else {
NCR_SlewTimes(records[i].data, cooked, dfreq, doffset);
NCR_SlewTimes(record->data, cooked, dfreq, doffset);
}
}
}
@@ -490,18 +794,20 @@ slew_sources(struct timeval *raw,
int
NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
{
int i;
SourceRecord *record;
unsigned int i;
int any;
NSR_ResolveSources();
any = 0;
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr) {
if (address->family == IPADDR_UNSPEC ||
!UTI_CompareIPs(&records[i].remote_addr->ip_addr, address, mask)) {
!UTI_CompareIPs(&record->remote_addr->ip_addr, address, mask)) {
any = 1;
NCR_TakeSourceOnline(records[i].data);
NCR_TakeSourceOnline(record->data);
}
}
}
@@ -510,8 +816,10 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
struct UnresolvedSource *us;
for (us = unresolved_sources; us; us = us->next) {
if (us->replacement)
continue;
any = 1;
us->params.online = 1;
us->new_source.params.online = 1;
}
}
@@ -523,35 +831,39 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
int
NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address)
{
int i, any, syncpeer;
SourceRecord *record, *syncpeer;
unsigned int i, any;
any = 0;
syncpeer = -1;
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
syncpeer = NULL;
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr) {
if (address->family == IPADDR_UNSPEC ||
!UTI_CompareIPs(&records[i].remote_addr->ip_addr, address, mask)) {
!UTI_CompareIPs(&record->remote_addr->ip_addr, address, mask)) {
any = 1;
if (NCR_IsSyncPeer(records[i].data)) {
syncpeer = i;
if (NCR_IsSyncPeer(record->data)) {
syncpeer = record;
continue;
}
NCR_TakeSourceOffline(records[i].data);
NCR_TakeSourceOffline(record->data);
}
}
}
/* Take sync peer offline as last to avoid reference switching */
if (syncpeer >= 0) {
NCR_TakeSourceOffline(records[syncpeer].data);
if (syncpeer) {
NCR_TakeSourceOffline(syncpeer->data);
}
if (address->family == IPADDR_UNSPEC) {
struct UnresolvedSource *us;
for (us = unresolved_sources; us; us = us->next) {
if (us->replacement)
continue;
any = 1;
us->params.online = 0;
us->new_source.params.online = 0;
}
}
@@ -572,7 +884,7 @@ NSR_ModifyMinpoll(IPAddr *address, int new_minpoll)
if (found == 0) {
return 0;
} else {
NCR_ModifyMinpoll(records[slot].data, new_minpoll);
NCR_ModifyMinpoll(get_record(slot)->data, new_minpoll);
return 1;
}
}
@@ -591,7 +903,7 @@ NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll)
if (found == 0) {
return 0;
} else {
NCR_ModifyMaxpoll(records[slot].data, new_maxpoll);
NCR_ModifyMaxpoll(get_record(slot)->data, new_maxpoll);
return 1;
}
}
@@ -610,7 +922,7 @@ NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay)
if (found == 0) {
return 0;
} else {
NCR_ModifyMaxdelay(records[slot].data, new_max_delay);
NCR_ModifyMaxdelay(get_record(slot)->data, new_max_delay);
return 1;
}
}
@@ -629,7 +941,7 @@ NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio)
if (found == 0) {
return 0;
} else {
NCR_ModifyMaxdelayratio(records[slot].data, new_max_delay_ratio);
NCR_ModifyMaxdelayratio(get_record(slot)->data, new_max_delay_ratio);
return 1;
}
}
@@ -648,7 +960,7 @@ NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio)
if (found == 0) {
return 0;
} else {
NCR_ModifyMaxdelaydevratio(records[slot].data, new_max_delay_dev_ratio);
NCR_ModifyMaxdelaydevratio(get_record(slot)->data, new_max_delay_dev_ratio);
return 1;
}
}
@@ -667,7 +979,7 @@ NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum)
if (found == 0) {
return 0;
} else {
NCR_ModifyMinstratum(records[slot].data, new_min_stratum);
NCR_ModifyMinstratum(get_record(slot)->data, new_min_stratum);
return 1;
}
}
@@ -686,7 +998,7 @@ NSR_ModifyPolltarget(IPAddr *address, int new_poll_target)
if (found == 0) {
return 0;
} else {
NCR_ModifyPolltarget(records[slot].data, new_poll_target);
NCR_ModifyPolltarget(get_record(slot)->data, new_poll_target);
return 1;
}
}
@@ -697,16 +1009,18 @@ int
NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples,
IPAddr *mask, IPAddr *address)
{
int i;
SourceRecord *record;
unsigned int i;
int any;
any = 0;
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr) {
if (address->family == IPADDR_UNSPEC ||
!UTI_CompareIPs(&records[i].remote_addr->ip_addr, address, mask)) {
!UTI_CompareIPs(&record->remote_addr->ip_addr, address, mask)) {
any = 1;
NCR_InitiateSampleBurst(records[i].data, n_good_samples, n_total_samples);
NCR_InitiateSampleBurst(record->data, n_good_samples, n_total_samples);
}
}
}
@@ -729,7 +1043,7 @@ NSR_ReportSource(RPT_SourceReport *report, struct timeval *now)
rem_addr.port = 0;
find_slot(&rem_addr, &slot, &found);
if (found) {
NCR_ReportSource(records[slot].data, report, now);
NCR_ReportSource(get_record(slot)->data, report, now);
} else {
report->poll = 0;
report->latest_meas_ago = 0;
@@ -741,7 +1055,8 @@ NSR_ReportSource(RPT_SourceReport *report, struct timeval *now)
void
NSR_GetActivityReport(RPT_ActivityReport *report)
{
int i;
SourceRecord *record;
unsigned int i;
struct UnresolvedSource *us;
report->online = 0;
@@ -749,9 +1064,10 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
report->burst_online = 0;
report->burst_offline = 0;
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
NCR_IncrementActivityCounters(records[i].data, &report->online, &report->offline,
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr) {
NCR_IncrementActivityCounters(record->data, &report->online, &report->offline,
&report->burst_online, &report->burst_offline);
}
}

View File

@@ -50,10 +50,10 @@ typedef enum {
/* Procedure to add a new server or peer source. */
extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
/* Procedure to add a new server or peer source with currently unknown address.
The name will be periodically resolved in exponentially increasing intervals
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 add a new server, peer source, or pool of servers specified by
name instead of address. The name is resolved in exponentially increasing
intervals until it succeeds or fails with a non-temporary error. */
extern void NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params);
/* Function type for handlers to be called back when an attempt
* (possibly unsuccessful) to resolve unresolved sources ends */
@@ -77,6 +77,9 @@ extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
/* Procedure to remove all sources */
extern void NSR_RemoveAllSources(void);
/* Procedure to try to find a replacement for a bad source */
extern void NSR_HandleBadSource(IPAddr *address);
/* 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, NTP_Local_Address *local_addr, int length);

View File

@@ -44,9 +44,8 @@ command_unpadded_length(CMD_Request *r)
return 0;
} else {
switch (type) {
case REQ_NULL:
return offsetof(CMD_Request, data);
return offsetof(CMD_Request, data.null.EOR);
case REQ_ONLINE:
return offsetof(CMD_Request, data.online.EOR);
case REQ_OFFLINE:
@@ -67,6 +66,8 @@ command_unpadded_length(CMD_Request *r)
return offsetof(CMD_Request, data.modify_maxdelaydevratio.EOR);
case REQ_MODIFY_MAXUPDATESKEW:
return offsetof(CMD_Request, data.modify_maxupdateskew.EOR);
case REQ_MODIFY_MAKESTEP:
return offsetof(CMD_Request, data.modify_makestep.EOR);
case REQ_LOGON :
return offsetof(CMD_Request, data.logon.EOR);
case REQ_SETTIME :
@@ -76,11 +77,11 @@ command_unpadded_length(CMD_Request *r)
case REQ_MANUAL :
return offsetof(CMD_Request, data.manual.EOR);
case REQ_N_SOURCES :
return offsetof(CMD_Request, data.n_sources.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_SOURCE_DATA :
return offsetof(CMD_Request, data.source_data.EOR);
case REQ_REKEY :
return offsetof(CMD_Request, data.rekey.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_ALLOW :
return offsetof(CMD_Request, data.allow_deny.EOR);
case REQ_ALLOWALL :
@@ -108,21 +109,21 @@ command_unpadded_length(CMD_Request *r)
case REQ_DEL_SOURCE :
return offsetof(CMD_Request, data.del_source.EOR);
case REQ_WRITERTC :
return offsetof(CMD_Request, data.writertc.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_DFREQ :
return offsetof(CMD_Request, data.dfreq.EOR);
case REQ_DOFFSET :
return offsetof(CMD_Request, data.doffset.EOR);
case REQ_TRACKING :
return offsetof(CMD_Request, data.tracking.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_SOURCESTATS :
return offsetof(CMD_Request, data.sourcestats.EOR);
case REQ_RTCREPORT :
return offsetof(CMD_Request, data.rtcreport.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_TRIMRTC :
return offsetof(CMD_Request, data.trimrtc.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_CYCLELOGS :
return offsetof(CMD_Request, data.cyclelogs.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_SUBNETS_ACCESSED :
case REQ_CLIENT_ACCESSES:
/* No longer supported */
@@ -130,21 +131,25 @@ command_unpadded_length(CMD_Request *r)
case REQ_CLIENT_ACCESSES_BY_INDEX:
return offsetof(CMD_Request, data.client_accesses_by_index.EOR);
case REQ_MANUAL_LIST:
return offsetof(CMD_Request, data.manual_list.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_MANUAL_DELETE:
return offsetof(CMD_Request, data.manual_delete.EOR);
case REQ_MAKESTEP:
return offsetof(CMD_Request, data.make_step.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_ACTIVITY:
return offsetof(CMD_Request, data.activity.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_RESELECT:
return offsetof(CMD_Request, data.reselect.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_RESELECTDISTANCE:
return offsetof(CMD_Request, data.reselect_distance.EOR);
case REQ_MODIFY_MINSTRATUM:
return offsetof(CMD_Request, data.modify_minstratum.EOR);
case REQ_MODIFY_POLLTARGET:
return offsetof(CMD_Request, data.modify_polltarget.EOR);
case REQ_SMOOTHING:
return offsetof(CMD_Request, data.null.EOR);
case REQ_SMOOTHTIME:
return offsetof(CMD_Request, data.smoothtime.EOR);
default:
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
assert(0);
@@ -215,6 +220,8 @@ PKL_CommandPaddingLength(CMD_Request *r)
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_MODIFY_MAKESTEP:
return PADDING_LENGTH(data.modify_makestep.EOR, data.null.EOR);
case REQ_LOGON:
return PADDING_LENGTH(data.logon.EOR, data.null.EOR);
case REQ_SETTIME:
@@ -224,11 +231,11 @@ PKL_CommandPaddingLength(CMD_Request *r)
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);
return PADDING_LENGTH(data.null.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);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_ALLOW:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_ALLOWALL:
@@ -256,21 +263,21 @@ PKL_CommandPaddingLength(CMD_Request *r)
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);
return PADDING_LENGTH(data.null.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);
return PADDING_LENGTH(data.null.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);
return PADDING_LENGTH(data.null.EOR, data.rtc.EOR);
case REQ_TRIMRTC:
return PADDING_LENGTH(data.trimrtc.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_CYCLELOGS:
return PADDING_LENGTH(data.cyclelogs.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_SUBNETS_ACCESSED:
case REQ_CLIENT_ACCESSES:
/* No longer supported */
@@ -278,21 +285,25 @@ PKL_CommandPaddingLength(CMD_Request *r)
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);
return PADDING_LENGTH(data.null.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);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_ACTIVITY:
return PADDING_LENGTH(data.activity.EOR, data.activity.EOR);
return PADDING_LENGTH(data.null.EOR, data.activity.EOR);
case REQ_RESELECT:
return PADDING_LENGTH(data.reselect.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.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);
case REQ_SMOOTHING:
return PADDING_LENGTH(data.null.EOR, data.smoothing.EOR);
case REQ_SMOOTHTIME:
return PADDING_LENGTH(data.smoothtime.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);
@@ -356,7 +367,8 @@ PKL_ReplyLength(CMD_Reply *r)
}
case RPY_ACTIVITY:
return offsetof(CMD_Reply, data.activity.EOR);
case RPY_SMOOTHING:
return offsetof(CMD_Reply, data.smoothing.EOR);
default:
assert(0);
}

View File

@@ -27,6 +27,7 @@
#include "config.h"
#include "array.h"
#include "refclock.h"
#include "reference.h"
#include "conf.h"
@@ -86,10 +87,8 @@ struct RCL_Instance_Record {
SRC_Instance source;
};
#define MAX_RCL_SOURCES 8
static struct RCL_Instance_Record refclocks[MAX_RCL_SOURCES];
static int n_sources = 0;
/* Array of RCL_Instance_Record */
static ARR_Instance refclocks;
static LOG_FileID logfileid;
@@ -112,12 +111,20 @@ static int filter_get_sample(struct MedianFilter *filter, struct timeval *sample
static void filter_slew_samples(struct MedianFilter *filter, struct timeval *when, double dfreq, double doffset);
static void filter_add_dispersion(struct MedianFilter *filter, double dispersion);
static RCL_Instance
get_refclock(unsigned int index)
{
return (RCL_Instance)ARR_GetElement(refclocks, index);
}
void
RCL_Initialise(void)
{
refclocks = ARR_CreateInstance(sizeof (struct RCL_Instance_Record));
CNF_AddRefclocks();
if (n_sources > 0) {
if (ARR_GetSize(refclocks) > 0) {
LCL_AddParameterChangeHandler(slew_samples, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
}
@@ -130,22 +137,25 @@ RCL_Initialise(void)
void
RCL_Finalise(void)
{
int i;
unsigned int i;
for (i = 0; i < n_sources; i++) {
RCL_Instance inst = (RCL_Instance)&refclocks[i];
for (i = 0; i < ARR_GetSize(refclocks); i++) {
RCL_Instance inst = get_refclock(i);
if (inst->driver->fini)
inst->driver->fini(inst);
filter_fini(&inst->filter);
Free(inst->driver_parameter);
SRC_DestroyInstance(inst->source);
}
if (n_sources > 0) {
if (ARR_GetSize(refclocks) > 0) {
LCL_RemoveParameterChangeHandler(slew_samples, NULL);
LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
}
ARR_DestroyInstance(refclocks);
}
int
@@ -153,10 +163,7 @@ RCL_AddRefclock(RefclockParameters *params)
{
int pps_source = 0;
RCL_Instance inst = &refclocks[n_sources];
if (n_sources == MAX_RCL_SOURCES)
return 0;
RCL_Instance inst = ARR_GetNewElement(refclocks);
if (strcmp(params->driver_name, "SHM") == 0) {
inst->driver = &RCL_SHM_driver;
@@ -219,8 +226,13 @@ RCL_AddRefclock(RefclockParameters *params)
inst->ref_id = params->ref_id;
else {
unsigned char ref[5] = { 0, 0, 0, 0, 0 };
unsigned int index = ARR_GetSize(refclocks) - 1;
snprintf((char *)ref, sizeof (ref), "%3.3s", params->driver_name);
ref[3] = index % 10 + '0';
if (index >= 10)
ref[2] = (index / 10) % 10 + '0';
snprintf((char *)ref, 5, "%3.3s%d", params->driver_name, n_sources % 10);
inst->ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
}
@@ -248,11 +260,12 @@ RCL_AddRefclock(RefclockParameters *params)
filter_init(&inst->filter, params->filter_length, params->max_dispersion);
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL);
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL,
params->min_samples, params->max_samples);
DEBUG_LOG(LOGF_Refclock, "refclock %s added poll=%d dpoll=%d filter=%d",
params->driver_name, inst->poll, inst->driver_poll, params->filter_length);
n_sources++;
DEBUG_LOG(LOGF_Refclock, "refclock %s refid=%s poll=%d dpoll=%d filter=%d",
params->driver_name, UTI_RefidToString(inst->ref_id),
inst->poll, inst->driver_poll, params->filter_length);
Free(params->driver_name);
@@ -262,20 +275,21 @@ RCL_AddRefclock(RefclockParameters *params)
void
RCL_StartRefclocks(void)
{
int i, j;
unsigned int i, j, n;
for (i = 0; i < n_sources; i++) {
RCL_Instance inst = &refclocks[i];
n = ARR_GetSize(refclocks);
for (i = 0; i < n; i++) {
RCL_Instance inst = get_refclock(i);
SRC_SetSelectable(inst->source);
SRC_SetActive(inst->source);
inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst);
if (inst->lock_ref) {
/* Replace lock refid with index to refclocks */
for (j = 0; j < n_sources && refclocks[j].ref_id != inst->lock_ref; j++)
for (j = 0; j < n && get_refclock(j)->ref_id != inst->lock_ref; j++)
;
inst->lock_ref = (j < n_sources) ? j : -1;
inst->lock_ref = j < n ? j : -1;
} else
inst->lock_ref = -1;
}
@@ -284,14 +298,14 @@ RCL_StartRefclocks(void)
void
RCL_ReportSource(RPT_SourceReport *report, struct timeval *now)
{
int i;
unsigned int i;
uint32_t ref_id;
assert(report->ip_addr.family == IPADDR_INET4);
ref_id = report->ip_addr.addr.in4;
for (i = 0; i < n_sources; i++) {
RCL_Instance inst = &refclocks[i];
for (i = 0; i < ARR_GetSize(refclocks); i++) {
RCL_Instance inst = get_refclock(i);
if (inst->ref_id == ref_id) {
report->poll = inst->poll;
report->mode = RPT_LOCAL_REFERENCE;
@@ -353,7 +367,9 @@ RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset,
UTI_AddDoubleToTimeval(sample_time, correction, &cooked_time);
dispersion += instance->precision;
if (!valid_sample_time(instance, sample_time))
/* Make sure the timestamp and offset provided by the driver are sane */
if (!UTI_IsTimeOffsetSane(sample_time, offset) ||
!valid_sample_time(instance, sample_time))
return 0;
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset, dispersion);
@@ -393,7 +409,8 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
UTI_AddDoubleToTimeval(pulse_time, correction, &cooked_time);
dispersion += instance->precision;
if (!valid_sample_time(instance, pulse_time))
if (!UTI_IsTimeOffsetSane(pulse_time, 0.0) ||
!valid_sample_time(instance, pulse_time))
return 0;
rate = instance->pps_rate;
@@ -409,16 +426,19 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
offset -= 1.0 / rate;
if (instance->lock_ref != -1) {
RCL_Instance lock_refclock;
struct timeval ref_sample_time;
double sample_diff, ref_offset, ref_dispersion, shift;
if (!filter_get_last_sample(&refclocks[instance->lock_ref].filter,
lock_refclock = get_refclock(instance->lock_ref);
if (!filter_get_last_sample(&lock_refclock->filter,
&ref_sample_time, &ref_offset, &ref_dispersion)) {
DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored no ref sample");
return 0;
}
ref_dispersion += filter_get_avg_sample_dispersion(&refclocks[instance->lock_ref].filter);
ref_dispersion += filter_get_avg_sample_dispersion(&lock_refclock->filter);
UTI_DiffTimevalsToDouble(&sample_diff, &cooked_time, &ref_sample_time);
if (fabs(sample_diff) >= 2.0 / rate) {
@@ -441,7 +461,7 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
return 0;
}
leap = refclocks[instance->lock_ref].leap_status;
leap = lock_refclock->leap_status;
DEBUG_LOG(LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f offdiff=%.9f samplediff=%.9f",
second, offset, ref_offset - offset, sample_diff);
@@ -479,15 +499,6 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
return 1;
}
static double
poll_interval(int poll)
{
if (poll >= 0)
return 1 << poll;
else
return 1.0 / (1 << -poll);
}
static int
valid_sample_time(RCL_Instance instance, struct timeval *tv)
{
@@ -496,9 +507,9 @@ valid_sample_time(RCL_Instance instance, struct timeval *tv)
LCL_ReadRawTime(&raw_time);
UTI_DiffTimevalsToDouble(&diff, &raw_time, tv);
if (diff < 0.0 || diff > poll_interval(instance->poll + 1)) {
DEBUG_LOG(LOGF_Refclock, "refclock sample not valid age=%.6f tv=%s",
diff, UTI_TimevalToString(tv));
if (diff < 0.0 || diff > UTI_Log2ToDouble(instance->poll + 1)) {
DEBUG_LOG(LOGF_Refclock, "%s refclock sample not valid age=%.6f tv=%s",
UTI_RefidToString(instance->ref_id), diff, UTI_TimevalToString(tv));
return 0;
}
return 1;
@@ -508,10 +519,12 @@ static int
pps_stratum(RCL_Instance instance, struct timeval *tv)
{
struct timeval ref_time;
int is_synchronised, stratum, i;
int is_synchronised, stratum;
unsigned int i;
double root_delay, root_dispersion;
NTP_Leap leap;
uint32_t ref_id;
RCL_Instance refclock;
REF_GetReferenceParams(tv, &is_synchronised, &leap, &stratum,
&ref_id, &ref_time, &root_delay, &root_dispersion);
@@ -522,9 +535,10 @@ pps_stratum(RCL_Instance instance, struct timeval *tv)
return stratum - 1;
/* Or the current source is another PPS refclock */
for (i = 0; i < n_sources; i++) {
if (refclocks[i].ref_id == ref_id &&
refclocks[i].pps_active && refclocks[i].lock_ref == -1)
for (i = 0; i < ARR_GetSize(refclocks); i++) {
refclock = get_refclock(i);
if (refclock->ref_id == ref_id &&
refclock->pps_active && refclock->lock_ref == -1)
return stratum - 1;
}
@@ -572,30 +586,30 @@ poll_timeout(void *arg)
}
}
inst->timeout_id = SCH_AddTimeoutByDelay(poll_interval(poll), poll_timeout, arg);
inst->timeout_id = SCH_AddTimeoutByDelay(UTI_Log2ToDouble(poll), poll_timeout, arg);
}
static void
slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything)
{
int i;
unsigned int i;
for (i = 0; i < n_sources; i++) {
for (i = 0; i < ARR_GetSize(refclocks); i++) {
if (change_type == LCL_ChangeUnknownStep)
filter_reset(&refclocks[i].filter);
filter_reset(&get_refclock(i)->filter);
else
filter_slew_samples(&refclocks[i].filter, cooked, dfreq, doffset);
filter_slew_samples(&get_refclock(i)->filter, cooked, dfreq, doffset);
}
}
static void
add_dispersion(double dispersion, void *anything)
{
int i;
unsigned int i;
for (i = 0; i < n_sources; i++)
filter_add_dispersion(&refclocks[i].filter, dispersion);
for (i = 0; i < ARR_GetSize(refclocks); i++)
filter_add_dispersion(&get_refclock(i)->filter, dispersion);
}
static void

View File

@@ -38,6 +38,8 @@ typedef struct {
int poll;
int filter_length;
int pps_rate;
int min_samples;
int max_samples;
uint32_t ref_id;
uint32_t lock_ref_id;
double offset;

View File

@@ -29,7 +29,7 @@
#include "refclock.h"
#if HAVE_PPSAPI
#if FEAT_PPS
#if defined(HAVE_SYS_TIMEPPS_H)
#include <sys/timepps.h>

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -50,7 +50,7 @@ static int our_leap_sec;
static int our_stratum;
static uint32_t our_ref_id;
static IPAddr our_ref_ip;
struct timeval our_ref_time; /* Stored relative to reference, NOT local time */
struct timeval our_ref_time;
static double our_skew;
static double our_residual_freq;
static double our_root_delay;
@@ -98,6 +98,17 @@ static double drift_file_age;
static void update_drift_file(double, double);
/* Leap second handling mode */
static REF_LeapMode leap_mode;
/* Flag indicating the clock was recently corrected for leap second and it may
not have correct time yet (missing 23:59:60 in the UTC time scale) */
static int leap_in_progress;
/* Timer for the leap second handler */
static int leap_timer_running;
static SCH_TimeoutID leap_timeout_id;
/* Name of a system timezone containing leap seconds occuring at midnight */
static char *leap_tzname;
static time_t last_tz_leap_check;
@@ -109,11 +120,6 @@ static LOG_FileID logfileid;
/* ================================================== */
/* Reference ID supplied when we are locally referenced */
#define LOCAL_REFERENCE_ID 0x7f7f0101UL
/* ================================================== */
/* Exponential moving averages of absolute clock frequencies
used as a fallback when synchronisation is lost. */
@@ -136,6 +142,7 @@ static double last_ref_update_interval;
/* ================================================== */
static NTP_Leap get_tz_leap(time_t when);
static void update_leap_status(NTP_Leap leap, time_t now, int reset);
/* ================================================== */
@@ -148,6 +155,9 @@ handle_slew(struct timeval *raw,
void *anything)
{
double delta;
struct timeval now;
UTI_AdjustTimeval(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
if (change_type == LCL_ChangeUnknownStep) {
last_ref_update.tv_sec = 0;
@@ -155,6 +165,13 @@ handle_slew(struct timeval *raw,
} else if (last_ref_update.tv_sec) {
UTI_AdjustTimeval(&last_ref_update, cooked, &last_ref_update, &delta, dfreq, doffset);
}
/* When the clock was stepped, check if that doesn't change our leap status
and also reset the leap timeout to undo the shift in the scheduler */
if (change_type != LCL_ChangeAdjust && our_leap_sec && !leap_in_progress) {
LCL_ReadRawTime(&now);
update_leap_status(our_leap_status, now.tv_sec, 1);
}
}
/* ================================================== */
@@ -217,11 +234,18 @@ REF_Initialise(void)
enable_local_stratum = CNF_AllowLocalReference(&local_stratum);
leap_timer_running = 0;
leap_in_progress = 0;
leap_mode = CNF_GetLeapSecMode();
/* Switch to step mode if the system driver doesn't support leap */
if (leap_mode == REF_LeapModeSystem && !LCL_CanSystemLeap())
leap_mode = REF_LeapModeStep;
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) {
/* Check that the timezone has good data for Jun 30 2012 and Dec 31 2012 */
if (get_tz_leap(1341014400) == LEAP_InsertSecond &&
get_tz_leap(1356912000) == LEAP_Normal) {
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);
@@ -263,9 +287,7 @@ REF_Initialise(void)
void
REF_Finalise(void)
{
if (our_leap_sec) {
LCL_SetLeap(0);
}
update_leap_status(LEAP_Unsynchronised, 0, 0);
if (drift_file) {
update_drift_file(LCL_ReadAbsoluteFrequency(), our_skew);
@@ -301,6 +323,14 @@ REF_SetModeEndHandler(REF_ModeEndHandler handler)
/* ================================================== */
REF_LeapMode
REF_GetLeapMode(void)
{
return leap_mode;
}
/* ================================================== */
static double
Sqr(double x)
{
@@ -403,14 +433,10 @@ update_fb_drifts(double freq_ppm, double update_interval)
fb_drift_timeout_id = -1;
}
if (update_interval < 0.0 || update_interval > last_ref_update_interval * 4.0)
if (update_interval < 1.0 || update_interval > last_ref_update_interval * 4.0)
return;
for (i = 0; i < fb_drift_max - fb_drift_min + 1; i++) {
/* Don't allow differences larger than 10 ppm */
if (fabs(freq_ppm - fb_drifts[i].freq) > 10.0)
fb_drifts[i].secs = 0.0;
secs = 1 << (i + fb_drift_min);
if (fb_drifts[i].secs < secs) {
/* Calculate average over 2 * secs interval before switching to
@@ -436,11 +462,12 @@ update_fb_drifts(double freq_ppm, double update_interval)
static void
fb_drift_timeout(void *arg)
{
assert(are_we_synchronised == 0);
assert(next_fb_drift >= fb_drift_min && next_fb_drift <= fb_drift_max);
fb_drift_timeout_id = -1;
DEBUG_LOG(LOGF_Reference, "Fallback drift %d active: %f ppm",
next_fb_drift, fb_drifts[next_fb_drift - fb_drift_min].freq);
LCL_SetAbsoluteFrequency(fb_drifts[next_fb_drift - fb_drift_min].freq);
REF_SetUnsynchronised();
}
@@ -657,7 +684,89 @@ get_tz_leap(time_t when)
/* ================================================== */
static void
update_leap_status(NTP_Leap leap, time_t now)
leap_end_timeout(void *arg)
{
leap_timer_running = 0;
leap_in_progress = 0;
our_leap_sec = 0;
if (leap_mode == REF_LeapModeSystem)
LCL_SetSystemLeap(0);
if (our_leap_status == LEAP_InsertSecond ||
our_leap_status == LEAP_DeleteSecond)
our_leap_status = LEAP_Normal;
}
/* ================================================== */
static void
leap_start_timeout(void *arg)
{
leap_in_progress = 1;
switch (leap_mode) {
case REF_LeapModeSystem:
DEBUG_LOG(LOGF_Reference, "Waiting for system clock leap second correction");
break;
case REF_LeapModeSlew:
LCL_NotifyLeap(our_leap_sec);
LCL_AccumulateOffset(our_leap_sec, 0.0);
LOG(LOGS_WARN, LOGF_Reference, "Adjusting system clock for leap second");
break;
case REF_LeapModeStep:
LCL_NotifyLeap(our_leap_sec);
LCL_ApplyStepOffset(our_leap_sec);
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped for leap second");
break;
case REF_LeapModeIgnore:
LOG(LOGS_WARN, LOGF_Reference, "Ignoring leap second");
break;
default:
break;
}
/* Wait until the leap second is over with some extra room to be safe */
leap_timeout_id = SCH_AddTimeoutByDelay(2.0, leap_end_timeout, NULL);
}
/* ================================================== */
static void
set_leap_timeout(time_t now)
{
struct timeval when;
/* Stop old timer if there is one */
if (leap_timer_running) {
SCH_RemoveTimeout(leap_timeout_id);
leap_timer_running = 0;
leap_in_progress = 0;
}
if (!our_leap_sec)
return;
/* Insert leap second at 0:00:00 UTC, delete at 23:59:59 UTC. If the clock
will be corrected by the system, timeout slightly sooner to be sure it
will happen before the system correction. */
when.tv_sec = (now / (24 * 3600) + 1) * (24 * 3600);
when.tv_usec = 0;
if (our_leap_sec < 0)
when.tv_sec--;
if (leap_mode == REF_LeapModeSystem) {
when.tv_sec--;
when.tv_usec = 500000;
}
leap_timeout_id = SCH_AddTimeout(&when, leap_start_timeout, NULL);
leap_timer_running = 1;
}
/* ================================================== */
static void
update_leap_status(NTP_Leap leap, time_t now, int reset)
{
int leap_sec;
@@ -680,9 +789,22 @@ update_leap_status(NTP_Leap leap, time_t now)
}
}
if (leap_sec != our_leap_sec && !REF_IsLeapSecondClose()) {
LCL_SetLeap(leap_sec);
if (reset || (leap_sec != our_leap_sec && !REF_IsLeapSecondClose())) {
our_leap_sec = leap_sec;
switch (leap_mode) {
case REF_LeapModeSystem:
LCL_SetSystemLeap(our_leap_sec);
/* Fall through */
case REF_LeapModeSlew:
case REF_LeapModeStep:
case REF_LeapModeIgnore:
set_leap_timeout(now);
break;
default:
assert(0);
break;
}
}
our_leap_status = leap;
@@ -920,14 +1042,16 @@ REF_SetReference(int stratum,
our_residual_freq = frequency;
}
update_leap_status(leap, raw_now.tv_sec);
update_leap_status(leap, raw_now.tv_sec, 0);
maybe_log_offset(our_offset, raw_now.tv_sec);
if (step_offset != 0.0) {
LCL_ApplyStepOffset(step_offset);
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset);
if (LCL_ApplyStepOffset(step_offset))
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset);
}
LCL_SetSyncStatus(are_we_synchronised, offset_sd, offset_sd + root_delay / 2.0 + root_dispersion);
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
write_log(&now,
@@ -953,6 +1077,7 @@ REF_SetReference(int stratum,
/* Update fallback drifts */
if (fb_drifts) {
update_fb_drifts(abs_freq_ppm, update_interval);
schedule_fb_drift(&now);
}
last_ref_update_interval = update_interval;
@@ -979,12 +1104,10 @@ REF_SetManualReference
double skew
)
{
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
... */
REF_SetReference(0, LEAP_Unsynchronised, 1, manual_refid, NULL,
only supposed to be used with the local source option, really.
Log as MANU in the tracking log, packets will have NTP_REFID_LOCAL. */
REF_SetReference(0, LEAP_Unsynchronised, 1, 0x4D414E55UL, NULL,
ref_time, offset, 0.0, frequency, skew, 0.0, 0.0);
}
@@ -1013,9 +1136,11 @@ REF_SetUnsynchronised(void)
schedule_fb_drift(&now);
}
update_leap_status(LEAP_Unsynchronised, 0);
update_leap_status(LEAP_Unsynchronised, 0, 0);
are_we_synchronised = 0;
LCL_SetSyncStatus(0, 0.0, 0.0);
write_log(&now,
"0.0.0.0",
0,
@@ -1057,7 +1182,7 @@ REF_GetReferenceParams
UTI_DiffTimevalsToDouble(&elapsed, local_time, &our_ref_time);
extra_dispersion = (our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError()) * elapsed;
*leap_status = our_leap_status;
*leap_status = !leap_in_progress ? our_leap_status : LEAP_Unsynchronised;
*ref_id = our_ref_id;
*ref_time = our_ref_time;
*root_delay = our_root_delay;
@@ -1068,10 +1193,10 @@ REF_GetReferenceParams
*is_synchronised = 1;
*stratum = local_stratum;
*ref_id = LOCAL_REFERENCE_ID;
*ref_id = NTP_REFID_LOCAL;
/* Make the reference time be now less a second - this will
scarcely affect the client, but will ensure that the transmit
timestamp cannot come before this (which would cause test 6 to
timestamp cannot come before this (which would cause test 7 to
fail in the client's read routine) if the local system clock's
read routine is broken in any way. */
*ref_time = *local_time;
@@ -1089,8 +1214,8 @@ REF_GetReferenceParams
*is_synchronised = 0;
*leap_status = LEAP_Unsynchronised;
*stratum = 0;
*ref_id = 0;
*stratum = NTP_MAX_STRATUM;
*ref_id = NTP_REFID_UNSYNC;
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
@@ -1111,12 +1236,20 @@ REF_GetOurStratum(void)
} else if (enable_local_stratum) {
return local_stratum;
} else {
return 16;
return NTP_MAX_STRATUM;
}
}
/* ================================================== */
double
REF_GetSkew(void)
{
return our_skew;
}
/* ================================================== */
void
REF_ModifyMaxupdateskew(double new_max_update_skew)
{
@@ -1125,6 +1258,15 @@ REF_ModifyMaxupdateskew(double new_max_update_skew)
/* ================================================== */
void
REF_ModifyMakestep(int limit, double threshold)
{
make_step_limit = limit;
make_step_threshold = threshold;
}
/* ================================================== */
void
REF_EnableLocal(int stratum)
{
@@ -1187,7 +1329,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
LCL_GetOffsetCorrection(&now_raw, &correction, NULL);
UTI_AddDoubleToTimeval(&now_raw, correction, &now_cooked);
rep->ref_id = 0;
rep->ref_id = NTP_REFID_UNSYNC;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = 0;
rep->leap_status = our_leap_status;
@@ -1219,7 +1361,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
} else if (enable_local_stratum) {
rep->ref_id = LOCAL_REFERENCE_ID;
rep->ref_id = NTP_REFID_LOCAL;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = local_stratum;
rep->ref_time = now_cooked;

View File

@@ -35,6 +35,14 @@
#include "ntp.h"
#include "reports.h"
/* Leap second handling modes */
typedef enum {
REF_LeapModeSystem,
REF_LeapModeSlew,
REF_LeapModeStep,
REF_LeapModeIgnore,
} REF_LeapMode;
/* Init function */
extern void REF_Initialise(void);
@@ -61,6 +69,9 @@ typedef void (*REF_ModeEndHandler)(int result);
/* Set the handler for being notified of mode ending */
extern void REF_SetModeEndHandler(REF_ModeEndHandler handler);
/* Get leap second handling mode */
extern REF_LeapMode REF_GetLeapMode(void);
/* Function which takes a local cooked time and returns the estimated
time of the reference. It also returns the other parameters
required for forming the outgoing NTP packet.
@@ -154,9 +165,15 @@ REF_SetUnsynchronised(void);
synchronised */
extern int REF_GetOurStratum(void);
/* Return the current skew */
extern double REF_GetSkew(void);
/* Modify the setting for the maximum skew we are prepared to allow updates on (in ppm). */
extern void REF_ModifyMaxupdateskew(double new_max_update_skew);
/* Modify makestep settings */
extern void REF_ModifyMakestep(int limit, double threshold);
extern void REF_EnableLocal(int stratum);
extern void REF_DisableLocal(void);
extern int REF_IsLocalActive(void);

View File

@@ -86,16 +86,6 @@ typedef struct {
double rtc_gain_rate_ppm;
} RPT_RTC_Report;
typedef struct {
unsigned long client_hits;
unsigned long peer_hits;
unsigned long cmd_hits_auth;
unsigned long cmd_hits_normal;
unsigned long cmd_hits_bad;
unsigned long last_ntp_hit_ago;
unsigned long last_cmd_hit_ago;
} RPT_ClientAccess_Report;
typedef struct {
IPAddr ip_addr;
unsigned long client_hits;
@@ -122,4 +112,14 @@ typedef struct {
int unresolved;
} RPT_ActivityReport;
typedef struct {
int active;
int leap_only;
double offset;
double freq_ppm;
double wander_ppm;
double last_update_ago;
double remaining_time;
} RPT_SmoothingReport;
#endif /* GOT_REPORTS_H */

6
rtc.c
View File

@@ -93,9 +93,9 @@ fallback_time_init(void)
LCL_ReadCookedTime(&now, NULL);
if (now.tv_sec < buf.st_mtime) {
LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime);
LOG(LOGS_INFO, LOGF_Rtc,
"System clock set from driftfile %s", drift_file);
if (LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime))
LOG(LOGS_INFO, LOGF_Rtc, "System clock set from driftfile %s",
drift_file);
}
}

View File

@@ -86,8 +86,8 @@ static int skip_interrupts;
measured, together with a 'trim' that compensates these values for
any steps made to the RTC to bring it back into line
occasionally. The trim is in seconds. */
static time_t rtc_sec[MAX_SAMPLES];
static double rtc_trim[MAX_SAMPLES];
static time_t *rtc_sec = NULL;
static double *rtc_trim = NULL;
/* Reference time, against which delta times on the RTC scale are measured */
static time_t rtc_ref;
@@ -95,7 +95,7 @@ static time_t rtc_ref;
/* System clock (gettimeofday) samples associated with the above
samples. */
static struct timeval system_times[MAX_SAMPLES];
static struct timeval *system_times = NULL;
/* Number of samples currently stored. */
static int n_samples;
@@ -530,6 +530,10 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
int
RTC_Linux_Initialise(void)
{
rtc_sec = MallocArray(time_t, MAX_SAMPLES);
rtc_trim = MallocArray(double, MAX_SAMPLES);
system_times = MallocArray(struct timeval, MAX_SAMPLES);
/* Setup details depending on configuration options */
setup_config();
@@ -588,6 +592,9 @@ RTC_Linux_Finalise(void)
(void) RTC_Linux_WriteParameters();
}
Free(rtc_sec);
Free(rtc_trim);
Free(system_times);
}
/* ================================================== */
@@ -1036,9 +1043,9 @@ RTC_Linux_TimePreInit(void)
/* Set system time only if the step is larger than 1 second */
if (fabs(sys_offset) >= 1.0) {
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error);
LCL_ApplyStepOffset(sys_offset);
if (LCL_ApplyStepOffset(sys_offset))
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error);
}
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");

24
sched.c
View File

@@ -30,6 +30,7 @@
#include "sysincl.h"
#include "array.h"
#include "sched.h"
#include "memory.h"
#include "util.h"
@@ -68,7 +69,7 @@ typedef struct {
SCH_ArbitraryArgument arg;
} FileHandlerEntry;
static FileHandlerEntry file_handlers[FD_SETSIZE];
static ARR_Instance file_handlers;
/* Timestamp when last select() returned */
static struct timeval last_select_ts, last_select_ts_raw;
@@ -134,6 +135,8 @@ SCH_Initialise(void)
FD_ZERO(&read_fds);
n_read_fds = 0;
file_handlers = ARR_CreateInstance(sizeof (FileHandlerEntry));
n_timer_queue_entries = 0;
next_tqe_id = 0;
@@ -157,6 +160,8 @@ SCH_Initialise(void)
void
SCH_Finalise(void) {
ARR_DestroyInstance(file_handlers);
initialised = 0;
}
@@ -166,6 +171,7 @@ void
SCH_AddInputFileHandler
(int fd, SCH_FileHandler handler, SCH_ArbitraryArgument arg)
{
FileHandlerEntry *ptr;
assert(initialised);
@@ -179,8 +185,12 @@ SCH_AddInputFileHandler
++n_read_fds;
file_handlers[fd].handler = handler;
file_handlers[fd].arg = arg;
if (ARR_GetSize(file_handlers) < fd + 1)
ARR_SetSize(file_handlers, fd + 1);
ptr = (FileHandlerEntry *)ARR_GetElement(file_handlers, fd);
ptr->handler = handler;
ptr->arg = arg;
FD_SET(fd, &read_fds);
@@ -320,6 +330,10 @@ SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArg
LCL_ReadRawTime(&now);
UTI_AddDoubleToTimeval(&now, delay, &then);
if (UTI_CompareTimevals(&now, &then) > 0) {
LOG_FATAL(LOGF_Scheduler, "Timeout overflow");
}
return SCH_AddTimeout(&then, handler, arg);
}
@@ -482,13 +496,15 @@ dispatch_timeouts(struct timeval *now) {
static void
dispatch_filehandlers(int nfh, fd_set *fhs)
{
FileHandlerEntry *ptr;
int fh = 0;
while (nfh > 0) {
if (FD_ISSET(fh, fhs)) {
/* This descriptor can be read from, dispatch its handler */
(file_handlers[fh].handler)(file_handlers[fh].arg);
ptr = (FileHandlerEntry *)ARR_GetElement(file_handlers, fh);
(ptr->handler)(ptr->arg);
/* Decrement number of readable files still to find */
--nfh;

342
smooth.c Normal file
View File

@@ -0,0 +1,342 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2015
*
* 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 time smoothing.
*/
#include "config.h"
#include "sysincl.h"
#include "conf.h"
#include "local.h"
#include "logging.h"
#include "reference.h"
#include "smooth.h"
#include "util.h"
/*
Time smoothing determines an offset that needs to be applied to the cooked
time to make it smooth for external observers. Observed offset and frequency
change slowly and there are no discontinuities. This can be used on an NTP
server to make it easier for the clients to track the time and keep their
clocks close together even when large offset or frequency corrections are
applied to the server's clock (e.g. after being offline for longer time).
Accumulated offset and frequency are smoothed out in three stages. In the
first stage, the frequency is changed at a constant rate (wander) up to a
maximum, in the second stage the frequency stays at the maximum for as long
as needed and in the third stage the frequency is brought back to zero.
|
max_freq +-------/--------\-------------
| /| |\
freq | / | | \
| / | | \
| / | | \
0 +--/----+--------+----\--------
| / | | | time
|/ | | |
stage 1 2 3
Integral of this function is the smoothed out offset. It's a continuous
piecewise polynomial with two quadratic parts and one linear.
*/
struct stage {
double wander;
double length;
};
#define NUM_STAGES 3
static struct stage stages[NUM_STAGES];
/* Enabled/disabled smoothing */
static int enabled;
/* Enabled/disabled mode where only leap seconds are smoothed out and normal
offset/frequency changes are ignored */
static int leap_only_mode;
/* Maximum skew/max_wander ratio to start updating offset and frequency */
#define UNLOCK_SKEW_WANDER_RATIO 10000
static int locked;
/* Maximum wander and frequency offset */
static double max_wander;
static double max_freq;
/* Frequency offset, time offset and the time of the last smoothing update */
static double smooth_freq;
static double smooth_offset;
static struct timeval last_update;
static void
get_smoothing(struct timeval *now, double *poffset, double *pfreq,
double *pwander)
{
double elapsed, length, offset, freq, wander;
int i;
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
offset = smooth_offset;
freq = smooth_freq;
wander = 0.0;
for (i = 0; i < NUM_STAGES; i++) {
if (elapsed <= 0.0)
break;
length = stages[i].length;
if (length >= elapsed)
length = elapsed;
wander = stages[i].wander;
offset -= length * (2.0 * freq + wander * length) / 2.0;
freq += wander * length;
elapsed -= length;
}
if (elapsed > 0.0) {
wander = 0.0;
offset -= elapsed * freq;
}
*poffset = offset;
*pfreq = freq;
if (pwander)
*pwander = wander;
}
static void
update_stages(void)
{
double s1, s2, s, l1, l2, l3, lc, f, f2;
int i, dir;
/* Prepare the three stages so that the integral of the frequency offset
is equal to the offset that should be smoothed out */
s1 = smooth_offset / max_wander;
s2 = smooth_freq * smooth_freq / (2.0 * max_wander * max_wander);
l1 = l2 = l3 = 0.0;
/* Calculate the lengths of the 1st and 3rd stage assuming there is no
frequency limit. If length of the 1st stage comes out negative, switch
its direction. */
for (dir = -1; dir <= 1; dir += 2) {
s = dir * s1 + s2;
if (s >= 0.0) {
l3 = sqrt(s);
l1 = l3 - dir * smooth_freq / max_wander;
if (l1 >= 0.0)
break;
}
}
assert(dir <= 1 && l1 >= 0.0 && l3 >= 0.0);
/* If the limit was reached, shorten 1st+3rd stages and set a 2nd stage */
f = dir * smooth_freq + l1 * max_wander - max_freq;
if (f > 0.0) {
lc = f / max_wander;
/* No 1st stage if the frequency is already above the maximum */
if (lc > l1) {
lc = l1;
f2 = dir * smooth_freq;
} else {
f2 = max_freq;
}
l2 = lc * (2.0 + f / f2);
l1 -= lc;
l3 -= lc;
}
stages[0].wander = dir * max_wander;
stages[0].length = l1;
stages[1].wander = 0.0;
stages[1].length = l2;
stages[2].wander = -dir * max_wander;
stages[2].length = l3;
for (i = 0; i < NUM_STAGES; i++) {
DEBUG_LOG(LOGF_Smooth, "Smooth stage %d wander %e length %f",
i + 1, stages[i].wander, stages[i].length);
}
}
static void
update_smoothing(struct timeval *now, double offset, double freq)
{
/* Don't accept offset/frequency until the clock has stabilized */
if (locked) {
if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO || leap_only_mode)
SMT_Activate(now);
return;
}
get_smoothing(now, &smooth_offset, &smooth_freq, NULL);
smooth_offset += offset;
smooth_freq = (smooth_freq - freq) / (1.0 - freq);
last_update = *now;
update_stages();
DEBUG_LOG(LOGF_Smooth, "Smooth offset %e freq %e", smooth_offset, smooth_freq);
}
static void
handle_slew(struct timeval *raw, struct timeval *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything)
{
double delta;
if (change_type == LCL_ChangeAdjust) {
if (leap_only_mode)
update_smoothing(cooked, 0.0, 0.0);
else
update_smoothing(cooked, doffset, dfreq);
}
UTI_AdjustTimeval(&last_update, cooked, &last_update, &delta, dfreq, doffset);
}
void SMT_Initialise(void)
{
CNF_GetSmooth(&max_freq, &max_wander, &leap_only_mode);
if (max_freq <= 0.0 || max_wander <= 0.0) {
enabled = 0;
return;
}
enabled = 1;
locked = 1;
/* Convert from ppm */
max_freq *= 1e-6;
max_wander *= 1e-6;
LCL_AddParameterChangeHandler(handle_slew, NULL);
}
void SMT_Finalise(void)
{
}
int SMT_IsEnabled(void)
{
return enabled;
}
double
SMT_GetOffset(struct timeval *now)
{
double offset, freq;
if (!enabled)
return 0.0;
get_smoothing(now, &offset, &freq, NULL);
return offset;
}
void
SMT_Activate(struct timeval *now)
{
if (!enabled || !locked)
return;
LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated%s", leap_only_mode ?
" (leap seconds only)" : "");
locked = 0;
last_update = *now;
}
void
SMT_Reset(struct timeval *now)
{
int i;
if (!enabled)
return;
smooth_offset = 0.0;
smooth_freq = 0.0;
last_update = *now;
for (i = 0; i < NUM_STAGES; i++)
stages[i].wander = stages[i].length = 0.0;
}
void
SMT_Leap(struct timeval *now, int leap)
{
/* When the leap-only mode is disabled, the leap second will be accumulated
in handle_slew() as a normal offset */
if (!enabled || !leap_only_mode)
return;
update_smoothing(now, leap, 0.0);
}
int
SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now)
{
double length, elapsed;
int i;
if (!enabled)
return 0;
report->active = !locked;
report->leap_only = leap_only_mode;
get_smoothing(now, &report->offset, &report->freq_ppm, &report->wander_ppm);
/* Convert to ppm and negate (positive values mean faster/speeding up) */
report->freq_ppm *= -1.0e6;
report->wander_ppm *= -1.0e6;
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
if (!locked && elapsed >= 0.0) {
for (i = 0, length = 0.0; i < NUM_STAGES; i++)
length += stages[i].length;
report->last_update_ago = elapsed;
report->remaining_time = elapsed < length ? length - elapsed : 0.0;
} else {
report->last_update_ago = 0.0;
report->remaining_time = 0.0;
}
return 1;
}

48
smooth.h Normal file
View File

@@ -0,0 +1,48 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2015
*
* 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.
*
**********************************************************************
=======================================================================
This module implements time smoothing.
*/
#ifndef GOT_SMOOTH_H
#define GOT_SMOOTH_H
#include "reports.h"
extern void SMT_Initialise(void);
extern void SMT_Finalise(void);
extern int SMT_IsEnabled(void);
extern double SMT_GetOffset(struct timeval *now);
extern void SMT_Activate(struct timeval *now);
extern void SMT_Reset(struct timeval *now);
extern void SMT_Leap(struct timeval *now, int leap);
extern int SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now);
#endif

944
sources.c

File diff suppressed because it is too large Load Diff

View File

@@ -65,7 +65,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(uint32_t 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, int min_samples, int max_samples);
/* Function to get rid of a source when it is being unconfigured.
This may cause the current reference source to be reselected, if this
@@ -74,6 +74,11 @@ extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_Se
extern void SRC_DestroyInstance(SRC_Instance instance);
/* Function to reset a source */
extern void SRC_ResetInstance(SRC_Instance instance);
/* Function to change the sources's reference ID and IP address */
extern void SRC_SetRefid(SRC_Instance instance, uint32_t ref_id, IPAddr *addr);
/* Function to get the range of frequencies, relative to the given
source, that we believe the local clock lies within. The return
@@ -104,7 +109,7 @@ extern void SRC_GetFrequencyRange(SRC_Instance instance, double *lo, double *hi)
indicates that the local clock is FAST relative to it.
root_delay and root_dispersion are in seconds, and are as per
RFC1305. root_dispersion only includes the peer's root dispersion
RFC 5905. root_dispersion only includes the peer's root dispersion
+ local sampling precision + skew dispersion accrued during the
measurement. It is the job of the source statistics algorithms +
track.c to add on the extra dispersion due to the residual standard
@@ -124,14 +129,6 @@ extern void SRC_SetActive(SRC_Instance inst);
/* This routine sets the source as not receiving reachability updates */
extern void SRC_UnsetActive(SRC_Instance inst);
/* This routine indicates that packets with valid headers are being
received from the designated source */
extern void SRC_SetSelectable(SRC_Instance instance);
/* This routine indicates that we are no longer receiving packets with
valid headers from the designated source */
extern void SRC_UnsetSelectable(SRC_Instance instance);
/* This routine updates the reachability register */
extern void SRC_UpdateReachability(SRC_Instance inst, int reachable);
@@ -140,11 +137,11 @@ extern void SRC_ResetReachability(SRC_Instance inst);
/* This routine is used to select the best source from amongst those
we currently have valid data on, and use it as the tracking base
for the local time. Updates are only made to the local reference
if a new source is selected or updated_inst is the selected
reference source. (This avoids updating the frequency
for the local time. Updates are made to the local reference only
when the selected source was updated (set as updated_inst) since
the last reference update. This avoids updating the frequency
tracking for every sample from other sources - only the ones from
the selected reference make a difference) */
the selected reference make a difference. */
extern void SRC_SelectSource(SRC_Instance updated_inst);
/* Force reselecting the best source */
@@ -180,14 +177,6 @@ extern int SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report, struc
extern SRC_Type SRC_GetType(int index);
typedef enum {
SRC_Skew_Decrease,
SRC_Skew_Nochange,
SRC_Skew_Increase
} SRC_Skew_Direction;
extern SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst);
extern int SRC_Samples(SRC_Instance inst);
#endif /* GOT_SOURCES_H */

View File

@@ -43,10 +43,6 @@
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)
@@ -68,6 +64,10 @@ struct SST_Stats_Record {
uint32_t refid;
IPAddr *ip_addr;
/* User defined minimum and maximum number of samples */
int min_samples;
int max_samples;
/* Number of samples currently stored. The samples are stored in circular
buffer. */
int n_samples;
@@ -108,9 +108,6 @@ struct SST_Stats_Record {
about estimated_frequency */
double skew;
/* This is the direction the skew went in at the last sample */
SST_Skew_Direction skew_dirn;
/* This is the estimated residual variance of the data points */
double variance;
@@ -122,8 +119,7 @@ struct SST_Stats_Record {
sample times. In this module, we use the convention that
positive means the local clock is FAST of the source and negative
means it is SLOW. This is contrary to the convention in the NTP
stuff; that part of the code is written to correspond with
RFC1305 conventions. */
stuff. */
double offsets[MAX_SAMPLES * REGRESS_RUNS_RATIO];
/* This is an array of the offsets as originally measured. Local
@@ -167,8 +163,6 @@ 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();
}
/* ================================================== */
@@ -182,13 +176,15 @@ SST_Finalise(void)
/* This function creates a new instance of the statistics handler */
SST_Stats
SST_CreateInstance(uint32_t refid, IPAddr *addr)
SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples)
{
SST_Stats inst;
inst = MallocNew(struct SST_Stats_Record);
inst->refid = refid;
inst->ip_addr = addr;
inst->min_samples = min_samples;
inst->max_samples = max_samples;
SST_SetRefid(inst, refid, addr);
SST_ResetInstance(inst);
return inst;
@@ -216,7 +212,6 @@ SST_ResetInstance(SST_Stats inst)
inst->min_delay_sample = 0;
inst->estimated_frequency = 0;
inst->skew = 2000.0e-6;
inst->skew_dirn = SST_Skew_Nochange;
inst->estimated_offset = 0.0;
inst->estimated_offset_sd = 86400.0; /* Assume it's at least within a day! */
inst->offset_time.tv_sec = 0;
@@ -225,6 +220,15 @@ SST_ResetInstance(SST_Stats inst)
inst->nruns = 0;
}
/* ================================================== */
void
SST_SetRefid(SST_Stats inst, uint32_t refid, IPAddr *addr)
{
inst->refid = refid;
inst->ip_addr = addr;
}
/* ================================================== */
/* This function is called to prune the register down when it is full.
For now, just discard the oldest sample. */
@@ -259,7 +263,7 @@ SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time,
/* Make room for the new sample */
if (inst->n_samples > 0 &&
(inst->n_samples == MAX_SAMPLES || inst->n_samples == max_samples)) {
(inst->n_samples == MAX_SAMPLES || inst->n_samples == inst->max_samples)) {
prune_register(inst, 1);
}
@@ -444,7 +448,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,
inst->min_samples,
&est_intercept, &est_slope, &est_var,
&est_intercept_sd, &est_slope_sd,
&best_start, &nruns, &degrees_of_freedom);
@@ -467,18 +471,6 @@ SST_DoNewRegression(SST_Stats inst)
stress = fabs(old_freq - inst->estimated_frequency) / old_skew;
if (best_start > 0) {
/* If we are throwing old data away, retain the current
assumptions about the skew */
inst->skew_dirn = SST_Skew_Nochange;
} else {
if (inst->skew < old_skew) {
inst->skew_dirn = SST_Skew_Decrease;
} else {
inst->skew_dirn = SST_Skew_Increase;
}
}
if (logfileid != -1) {
LOG_FileWrite(logfileid, "%s %-15s %10.3e %10.3e %10.3e %10.3e %10.3e %7.1e %3d %3d %3d",
UTI_TimeToLogForm(inst->offset_time.tv_sec),
@@ -537,11 +529,19 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
double *offset_lo_limit,
double *offset_hi_limit,
double *root_distance,
double *variance, int *select_ok)
double *variance,
double *first_sample_ago,
double *last_sample_ago,
int *select_ok)
{
double offset, sample_elapsed;
int i, j;
if (!inst->n_samples) {
*select_ok = 0;
return;
}
i = get_runsbuf_index(inst, inst->best_single_sample);
j = get_buf_index(inst, inst->best_single_sample);
@@ -570,10 +570,16 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
}
#endif
i = get_runsbuf_index(inst, 0);
UTI_DiffTimevalsToDouble(first_sample_ago, now, &inst->sample_times[i]);
i = get_runsbuf_index(inst, inst->n_samples - 1);
UTI_DiffTimevalsToDouble(last_sample_ago, now, &inst->sample_times[i]);
*select_ok = inst->regression_ok;
DEBUG_LOG(LOGF_SourceStats, "n=%d off=%f dist=%f var=%f selok=%d",
inst->n_samples, offset, *root_distance, *variance, *select_ok);
DEBUG_LOG(LOGF_SourceStats, "n=%d off=%f dist=%f var=%f first_ago=%f last_ago=%f selok=%d",
inst->n_samples, offset, *root_distance, *variance,
*first_sample_ago, *last_sample_ago, *select_ok);
}
/* ================================================== */
@@ -625,27 +631,23 @@ SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffs
sample = &(inst->sample_times[i]);
prev = *sample;
UTI_AdjustTimeval(sample, when, sample, &delta_time, dfreq, doffset);
prev_offset = inst->offsets[i];
inst->offsets[i] += delta_time;
DEBUG_LOG(LOGF_SourceStats, "i=%d old_st=[%s] new_st=[%s] old_off=%f new_off=%f",
i, UTI_TimevalToString(&prev), UTI_TimevalToString(sample),
prev_offset, inst->offsets[i]);
}
/* Do a half-baked update to the regression estimates */
/* Update the regression estimates */
prev = inst->offset_time;
prev_offset = inst->estimated_offset;
prev_freq = inst->estimated_frequency;
UTI_AdjustTimeval(&(inst->offset_time), when, &(inst->offset_time),
&delta_time, dfreq, doffset);
inst->estimated_offset += delta_time;
inst->estimated_frequency -= dfreq;
inst->estimated_frequency = (inst->estimated_frequency - dfreq) / (1.0 - dfreq);
DEBUG_LOG(LOGF_SourceStats, "old_off_time=[%s] new=[%s] old_off=%f new_off=%f old_freq=%.3fppm new_freq=%.3fppm",
UTI_TimevalToString(&prev), UTI_TimevalToString(&(inst->offset_time)),
prev_offset, inst->estimated_offset,
1.0e6*prev_freq, 1.0e6*inst->estimated_frequency);
DEBUG_LOG(LOGF_SourceStats, "n=%d m=%d old_off_time=%s new=%s old_off=%f new_off=%f old_freq=%.3f new_freq=%.3f",
inst->n_samples, inst->runs_samples,
UTI_TimevalToString(&prev), UTI_TimevalToString(&(inst->offset_time)),
prev_offset, inst->estimated_offset,
1.0e6 * prev_freq, 1.0e6 * inst->estimated_frequency);
}
/* ================================================== */
@@ -851,14 +853,6 @@ SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timeval *now
}
}
/* ================================================== */
SST_Skew_Direction SST_LastSkewChange(SST_Stats inst)
{
return inst->skew_dirn;
}
/* ================================================== */
int

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(uint32_t refid, IPAddr *addr);
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples);
/* This function deletes an instance of the statistics handler. */
extern void SST_DeleteInstance(SST_Stats inst);
@@ -46,6 +46,9 @@ extern void SST_DeleteInstance(SST_Stats inst);
/* This function resets an instance */
extern void SST_ResetInstance(SST_Stats inst);
/* This function changes the reference ID and IP address */
extern void SST_SetRefid(SST_Stats inst, uint32_t refid, IPAddr *addr);
/* This function accumulates a single sample into the statistics handler
sample_time is the epoch at which the sample is to be considered to
@@ -55,10 +58,6 @@ extern void SST_ResetInstance(SST_Stats inst);
seconds. Positive indicates that the local clock if FAST (contrary
to the NTP parts of the software)
root_distance is the Lambda+Delta/2 term in RFC1305, but excluding
the extra dispersion due to the residual standard deviation after
we have done the regression fit.
stratum is the stratum of the source from which the sample came.
*/
@@ -83,7 +82,10 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
double *offset_lo_limit,
double *offset_hi_limit,
double *root_distance,
double *variance, int *select_ok);
double *variance,
double *first_sample_ago,
double *last_sample_ago,
int *select_ok);
/* Get data needed when setting up tracking on this source */
extern void
@@ -135,14 +137,6 @@ extern void SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct
extern void SST_DoSourcestatsReport(SST_Stats inst, RPT_SourcestatsReport *report, struct timeval *now);
typedef enum {
SST_Skew_Decrease,
SST_Skew_Nochange,
SST_Skew_Increase
} SST_Skew_Direction;
extern SST_Skew_Direction SST_LastSkewChange(SST_Stats inst);
extern int SST_Samples(SST_Stats inst);
#endif /* GOT_SOURCESTATS_H */

View File

@@ -38,7 +38,11 @@ typedef struct {
int iburst;
int min_stratum;
int poll_target;
unsigned long authkey;
int version;
int max_sources;
int min_samples;
int max_samples;
uint32_t authkey;
double max_delay;
double max_delay_ratio;
double max_delay_dev_ratio;
@@ -49,11 +53,14 @@ typedef struct {
#define SRC_DEFAULT_MINPOLL 6
#define SRC_DEFAULT_MAXPOLL 10
#define SRC_DEFAULT_PRESEND_MINPOLL 0
#define SRC_DEFAULT_MAXDELAY 16.0
#define SRC_DEFAULT_MAXDELAY 3.0
#define SRC_DEFAULT_MAXDELAYRATIO 0.0
#define SRC_DEFAULT_MAXDELAYDEVRATIO 10.0
#define SRC_DEFAULT_MINSTRATUM 0
#define SRC_DEFAULT_POLLTARGET 6
#define INACTIVE_AUTHKEY 0UL
#define SRC_DEFAULT_MAXSOURCES 4
#define SRC_DEFAULT_MINSAMPLES (-1)
#define SRC_DEFAULT_MAXSAMPLES (-1)
#define INACTIVE_AUTHKEY 0
#endif /* GOT_SRCPARAMS_H */

329
stubs.c Normal file
View File

@@ -0,0 +1,329 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014
*
* 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.
*
**********************************************************************
=======================================================================
Function replacements needed when optional features are disabled.
*/
#include "config.h"
#include "clientlog.h"
#include "cmdmon.h"
#include "keys.h"
#include "logging.h"
#include "manual.h"
#include "nameserv.h"
#include "nameserv_async.h"
#include "ntp_core.h"
#include "ntp_io.h"
#include "ntp_sources.h"
#include "refclock.h"
#ifndef FEAT_ASYNCDNS
#define MAX_ADDRESSES 16
/* This is a blocking implementation used when asynchronous resolving is not available */
void
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
{
IPAddr addrs[MAX_ADDRESSES];
DNS_Status status;
int i;
status = DNS_Name2IPAddress(name, addrs, MAX_ADDRESSES);
for (i = 0; status == DNS_Success && i < MAX_ADDRESSES &&
addrs[i].family != IPADDR_UNSPEC; i++)
;
(handler)(status, i, addrs, anything);
}
#endif /* !FEAT_ASYNCDNS */
#ifndef FEAT_CMDMON
void
CAM_Initialise(int family)
{
}
void
CAM_Finalise(void)
{
}
int
CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
{
return 1;
}
void
MNL_Initialise(void)
{
}
void
MNL_Finalise(void)
{
}
#endif /* !FEAT_CMDMON */
#ifndef FEAT_NTP
void
NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
{
}
void
NCR_Initialise(void)
{
}
void
NCR_Finalise(void)
{
}
int
NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
{
return 1;
}
int
NCR_CheckAccessRestriction(IPAddr *ip_addr)
{
return 0;
}
void
NIO_Initialise(int family)
{
}
void
NIO_Finalise(void)
{
}
void
NSR_Initialise(void)
{
}
void
NSR_Finalise(void)
{
}
NSR_Status
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
{
return NSR_TooManySources;
}
void
NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params)
{
}
NSR_Status
NSR_RemoveSource(NTP_Remote_Address *remote_addr)
{
return NSR_NoSuchSource;
}
void
NSR_RemoveAllSources(void)
{
}
void
NSR_HandleBadSource(IPAddr *address)
{
}
void
NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler)
{
if (handler)
(handler)();
}
void
NSR_ResolveSources(void)
{
}
void NSR_StartSources(void)
{
}
void NSR_AutoStartSources(void)
{
}
int
NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples,
IPAddr *mask, IPAddr *address)
{
return 0;
}
int
NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
{
return 0;
}
int
NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address)
{
return 0;
}
int
NSR_ModifyMinpoll(IPAddr *address, int new_minpoll)
{
return 0;
}
int
NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll)
{
return 0;
}
int
NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay)
{
return 0;
}
int
NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio)
{
return 0;
}
int
NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio)
{
return 0;
}
int
NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum)
{
return 0;
}
int
NSR_ModifyPolltarget(IPAddr *address, int new_poll_target)
{
return 0;
}
void
NSR_ReportSource(RPT_SourceReport *report, struct timeval *now)
{
memset(report, 0, sizeof (*report));
}
void
NSR_GetActivityReport(RPT_ActivityReport *report)
{
memset(report, 0, sizeof (*report));
}
#ifndef FEAT_CMDMON
void
CLG_Initialise(void)
{
}
void
CLG_Finalise(void)
{
}
void
DNS_SetAddressFamily(int family)
{
}
DNS_Status
DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
{
return DNS_Failure;
}
void
KEY_Initialise(void)
{
}
void
KEY_Finalise(void)
{
}
#endif /* !FEAT_CMDMON */
#endif /* !FEAT_NTP */
#ifndef FEAT_REFCLOCK
void
RCL_Initialise(void)
{
}
void
RCL_Finalise(void)
{
}
int
RCL_AddRefclock(RefclockParameters *params)
{
return 0;
}
void
RCL_StartRefclocks(void)
{
}
void
RCL_ReportSource(RPT_SourceReport *report, struct timeval *now)
{
memset(report, 0, sizeof (*report));
}
#endif /* !FEAT_REFCLOCK */

14
sys.c
View File

@@ -46,6 +46,10 @@
#include "sys_netbsd.h"
#endif
#if defined (MACOSX)
#include "sys_macosx.h"
#endif
/* ================================================== */
void
@@ -68,6 +72,10 @@ SYS_Initialise(void)
SYS_NetBSD_Initialise();
#endif
#if defined(MACOSX)
SYS_MacOSX_Initialise();
#endif
}
/* ================================================== */
@@ -91,13 +99,17 @@ SYS_Finalise(void)
#if defined(__NetBSD__)
SYS_NetBSD_Finalise();
#endif
#if defined(MACOSX)
SYS_MacOSX_Finalise();
#endif
}
/* ================================================== */
void SYS_DropRoot(char *user)
{
#if defined(LINUX) && defined (FEAT_LINUXCAPS)
#if defined(LINUX) && defined (FEAT_PRIVDROP)
SYS_Linux_DropRoot(user);
#else
LOG_FATAL(LOGF_Sys, "dropping root privileges not supported");

View File

@@ -39,9 +39,10 @@
/* ================================================== */
/* System clock frequency drivers */
/* System clock drivers */
static lcl_ReadFrequencyDriver drv_read_freq;
static lcl_SetFrequencyDriver drv_set_freq;
static lcl_SetSyncStatusDriver drv_set_sync_status;
/* Current frequency as requested by the local module (in ppm) */
static double base_freq;
@@ -106,6 +107,18 @@ handle_step(struct timeval *raw, struct timeval *cooked, double dfreq,
}
}
/* ================================================== */
static double
clamp_freq(double freq)
{
if (freq > max_freq)
return max_freq;
if (freq < -max_freq)
return -max_freq;
return freq;
}
/* ================================================== */
/* End currently running slew and start a new one */
@@ -143,11 +156,7 @@ update_slew(void)
corr_freq = max_corr_freq;
/* Get the new real frequency and clamp it */
total_freq = base_freq + corr_freq * (1.0e6 - base_freq);
if (total_freq > max_freq)
total_freq = max_freq;
else if (total_freq < -max_freq)
total_freq = -max_freq;
total_freq = clamp_freq(base_freq + corr_freq * (1.0e6 - base_freq));
/* Set the new frequency (the actual frequency returned by the call may be
slightly different from the requested frequency due to rounding) */
@@ -249,7 +258,7 @@ offset_convert(struct timeval *raw,
/* ================================================== */
/* Positive means currently fast of true time, i.e. jump backwards */
static void
static int
apply_step_offset(double offset)
{
struct timeval old_time, new_time;
@@ -259,13 +268,32 @@ apply_step_offset(double offset)
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysGeneric, "settimeofday() failed");
DEBUG_LOG(LOGF_SysGeneric, "settimeofday() failed");
return 0;
}
LCL_ReadRawTime(&old_time);
UTI_DiffTimevalsToDouble(&err, &old_time, &new_time);
lcl_InvokeDispersionNotifyHandlers(fabs(err));
return 1;
}
/* ================================================== */
static void
set_sync_status(int synchronised, double est_error, double max_error)
{
double offset;
offset = fabs(offset_register);
if (est_error < offset)
est_error = offset;
max_error += offset;
if (drv_set_sync_status)
drv_set_sync_status(synchronised, est_error, max_error);
}
/* ================================================== */
@@ -275,12 +303,14 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
lcl_ReadFrequencyDriver sys_read_freq,
lcl_SetFrequencyDriver sys_set_freq,
lcl_ApplyStepOffsetDriver sys_apply_step_offset,
lcl_SetLeapDriver sys_set_leap)
lcl_SetLeapDriver sys_set_leap,
lcl_SetSyncStatusDriver sys_set_sync_status)
{
max_freq = max_set_freq_ppm;
max_freq_change_delay = max_set_freq_delay * (1.0 + max_freq / 1.0e6);
drv_read_freq = sys_read_freq;
drv_set_freq = sys_set_freq;
drv_set_sync_status = sys_set_sync_status;
base_freq = (*drv_read_freq)();
slew_freq = 0.0;
@@ -291,7 +321,7 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, sys_apply_step_offset ?
sys_apply_step_offset : apply_step_offset,
offset_convert, sys_set_leap);
offset_convert, sys_set_leap, set_sync_status);
LCL_AddParameterChangeHandler(handle_step, NULL);
}
@@ -308,7 +338,7 @@ SYS_Generic_Finalise(void)
slew_timer_running = 0;
}
(*drv_set_freq)(base_freq);
(*drv_set_freq)(clamp_freq(base_freq));
}
/* ================================================== */

View File

@@ -35,7 +35,8 @@ extern void SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_s
lcl_ReadFrequencyDriver sys_read_freq,
lcl_SetFrequencyDriver sys_set_freq,
lcl_ApplyStepOffsetDriver sys_apply_step_offset,
lcl_SetLeapDriver sys_set_leap);
lcl_SetLeapDriver sys_set_leap,
lcl_SetSyncStatusDriver sys_set_sync_status);
extern void SYS_Generic_Finalise(void);

View File

@@ -44,7 +44,7 @@ int SchedPriority = 0;
int LockAll = 0;
#endif
#ifdef FEAT_LINUXCAPS
#ifdef FEAT_PRIVDROP
#include <sys/types.h>
#include <pwd.h>
#include <sys/prctl.h>
@@ -58,6 +58,9 @@ int LockAll = 0;
#include "logging.h"
#include "wrap_adjtimex.h"
/* The threshold for adjtimex maxerror when the kernel sets the UNSYNC flag */
#define UNSYNC_MAXERROR 16.0
/* This is the uncompensated system tick value */
static int nominal_tick;
@@ -82,25 +85,30 @@ static int tick_update_hz;
/* ================================================== */
inline static long
our_round(double x) {
our_round(double x)
{
long y;
if (x > 0.0)
y = x + 0.5;
y = x + 0.5;
else
y = x - 0.5;
y = x - 0.5;
return y;
}
/* ================================================== */
/* Positive means currently fast of true time, i.e. jump backwards */
static void
static int
apply_step_offset(double offset)
{
if (TMX_ApplyStepOffset(-offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
DEBUG_LOG(LOGF_SysLinux, "adjtimex() failed");
return 0;
}
return 1;
}
/* ================================================== */
@@ -169,6 +177,15 @@ read_frequency(void)
static void
set_leap(int leap)
{
int current_leap;
if (TMX_GetLeap(&current_leap) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed in set_leap");
}
if (current_leap == leap)
return;
if (TMX_SetLeap(leap) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed in set_leap");
}
@@ -179,21 +196,42 @@ set_leap(int leap)
/* ================================================== */
static void
set_sync_status(int synchronised, double est_error, double max_error)
{
if (synchronised) {
if (est_error > UNSYNC_MAXERROR)
est_error = UNSYNC_MAXERROR;
if (max_error >= UNSYNC_MAXERROR) {
max_error = UNSYNC_MAXERROR;
synchronised = 0;
}
} else {
est_error = max_error = UNSYNC_MAXERROR;
}
/* Clear the UNSYNC flag only if rtcsync is enabled */
if (!CNF_GetRtcSync())
synchronised = 0;
TMX_SetSync(synchronised, est_error, max_error);
}
/* ================================================== */
/* Estimate the value of USER_HZ given the value of txc.tick that chronyd finds when
* it starts. The only credible values are 100 (Linux/x86) or powers of 2.
* Also, the bounds checking inside the kernel's adjtimex system call enforces
* a +/- 10% movement of tick away from the nominal value 1e6/USER_HZ. */
static void
guess_hz_and_shift_hz(int tick, int *hz, int *shift_hz)
static int
guess_hz(int tick)
{
int i, tick_lo, tick_hi, ihz;
double tick_nominal;
/* Pick off the hz=100 case first */
if (tick >= 9000 && tick <= 11000) {
*hz = 100;
*shift_hz = 7;
return;
return 100;
}
for (i=4; i<16; i++) { /* surely 16 .. 32768 is a wide enough range? */
@@ -203,36 +241,26 @@ guess_hz_and_shift_hz(int tick, int *hz, int *shift_hz)
tick_hi = (int)(0.5 + tick_nominal*4.0/3.0);
if (tick_lo < tick && tick <= tick_hi) {
*hz = ihz;
*shift_hz = i;
return;
return ihz;
}
}
/* oh dear. doomed. */
*hz = 0;
*shift_hz = 0;
return 0;
}
/* ================================================== */
static int
get_hz_and_shift_hz(int *hz, int *shift_hz)
get_hz(void)
{
#ifdef _SC_CLK_TCK
if ((*hz = sysconf(_SC_CLK_TCK)) < 1) {
int hz;
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;
return hz;
#else
return 0;
#endif
@@ -259,19 +287,20 @@ static void
get_version_specific_details(void)
{
int major, minor, patch;
int shift_hz;
struct tmx_params tmx_params;
long tick;
double freq;
struct utsname uts;
if (!get_hz_and_shift_hz(&hz, &shift_hz)) {
TMX_ReadCurrentParams(&tmx_params);
hz = get_hz();
guess_hz_and_shift_hz(tmx_params.tick, &hz, &shift_hz);
if (!hz) {
if (TMX_GetFrequency(&freq, &tick) < 0)
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
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);
}
hz = guess_hz(tick);
if (!hz)
LOG_FATAL(LOGF_SysLinux, "Can't determine hz from tick %ld", tick);
}
dhz = (double) hz;
@@ -332,13 +361,11 @@ SYS_Linux_Initialise(void)
have_setoffset = 0;
}
TMX_SetSync(CNF_GetRtcSync());
SYS_Generic_CompleteFreqDriver(1.0e6 * max_tick_bias / nominal_tick,
1.0 / tick_update_hz,
read_frequency, set_frequency,
have_setoffset ? apply_step_offset : NULL,
set_leap);
set_leap, set_sync_status);
}
/* ================================================== */
@@ -352,7 +379,7 @@ SYS_Linux_Finalise(void)
/* ================================================== */
#ifdef FEAT_LINUXCAPS
#ifdef FEAT_PRIVDROP
void
SYS_Linux_DropRoot(char *user)
{
@@ -382,7 +409,7 @@ SYS_Linux_DropRoot(char *user)
LOG_FATAL(LOGF_SysLinux, "setuid(%d) failed", pw->pw_uid);
}
if ((cap = cap_from_text("cap_sys_time=ep")) == NULL) {
if ((cap = cap_from_text("cap_net_bind_service,cap_sys_time=ep")) == NULL) {
LOG_FATAL(LOGF_SysLinux, "cap_from_text() failed");
}

314
sys_macosx.c Normal file
View File

@@ -0,0 +1,314 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2001
* Copyright (C) J. Hannken-Illjes 2001
* Copyright (C) Bryan Christianson 2015
*
* 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.
*
**********************************************************************
=======================================================================
Driver file for the MacOS X operating system.
*/
#include "config.h"
#ifdef MACOSX
#include <sys/sysctl.h>
#include <sys/time.h>
#include <nlist.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/time.h>
#include <stdio.h>
#include <signal.h>
#include "sys_macosx.h"
#include "localp.h"
#include "logging.h"
#include "util.h"
/* ================================================== */
/* This register contains the number of seconds by which the local
clock was estimated to be fast of reference time at the epoch when
gettimeofday() returned T0 */
static double offset_register;
/* This register contains the epoch to which the offset is referenced */
static struct timeval T0;
/* This register contains the current estimate of the system
frequency, in absolute (NOT ppm) */
static double current_freq;
/* This register contains the number of seconds of adjustment that
were passed to adjtime last time it was called. */
static double adjustment_requested;
/* Kernel parameters to calculate adjtime error. */
static int kern_tickadj;
static long kern_bigadj;
/* ================================================== */
static void
clock_initialise(void)
{
struct timeval newadj, oldadj;
offset_register = 0.0;
adjustment_requested = 0.0;
current_freq = 0.0;
if (gettimeofday(&T0, NULL) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
}
newadj.tv_sec = 0;
newadj.tv_usec = 0;
if (adjtime(&newadj, &oldadj) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
}
}
/* ================================================== */
static void
clock_finalise(void)
{
/* Nothing to do yet */
}
/* ================================================== */
static void
start_adjust(void)
{
struct timeval newadj, oldadj;
struct timeval T1;
double elapsed, accrued_error;
double adjust_required;
struct timeval exact_newadj;
long delta, tickdelta;
double rounding_error;
double old_adjust_remaining;
/* Determine the amount of error built up since the last adjustment */
if (gettimeofday(&T1, NULL) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
accrued_error = elapsed * current_freq;
adjust_required = - (accrued_error + offset_register);
UTI_DoubleToTimeval(adjust_required, &exact_newadj);
/* At this point, we need to round the required adjustment the
same way the kernel does. */
delta = exact_newadj.tv_sec * 1000000 + exact_newadj.tv_usec;
if (delta > kern_bigadj || delta < -kern_bigadj)
tickdelta = 10 * kern_tickadj;
else
tickdelta = kern_tickadj;
if (delta % tickdelta)
delta = delta / tickdelta * tickdelta;
newadj.tv_sec = 0;
newadj.tv_usec = (int)delta;
UTI_NormaliseTimeval(&newadj);
/* Add rounding error back onto offset register. */
UTI_DiffTimevalsToDouble(&rounding_error, &newadj, &exact_newadj);
if (adjtime(&newadj, &oldadj) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
}
UTI_TimevalToDouble(&oldadj, &old_adjust_remaining);
offset_register = rounding_error - old_adjust_remaining;
T0 = T1;
UTI_TimevalToDouble(&newadj, &adjustment_requested);
}
/* ================================================== */
static void
stop_adjust(void)
{
struct timeval T1;
struct timeval zeroadj, remadj;
double adjustment_remaining, adjustment_achieved;
double elapsed, elapsed_plus_adjust;
zeroadj.tv_sec = 0;
zeroadj.tv_usec = 0;
if (adjtime(&zeroadj, &remadj) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
}
if (gettimeofday(&T1, NULL) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
UTI_TimevalToDouble(&remadj, &adjustment_remaining);
adjustment_achieved = adjustment_requested - adjustment_remaining;
elapsed_plus_adjust = elapsed - adjustment_achieved;
offset_register += current_freq * elapsed_plus_adjust - adjustment_remaining;
adjustment_requested = 0.0;
T0 = T1;
}
/* ================================================== */
/* Positive offset means system clock is fast of true time, therefore
slew backwards */
static void
accrue_offset(double offset, double corr_rate)
{
stop_adjust();
offset_register += offset;
start_adjust();
}
/* ================================================== */
/* Positive offset means system clock is fast of true time, therefore
step backwards */
static int
apply_step_offset(double offset)
{
struct timeval old_time, new_time, T1;
stop_adjust();
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
}
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
DEBUG_LOG(LOGF_SysMacOSX, "settimeofday() failed");
return 0;
}
UTI_AddDoubleToTimeval(&T0, offset, &T1);
T0 = T1;
start_adjust();
return 1;
}
/* ================================================== */
static double
set_frequency(double new_freq_ppm)
{
stop_adjust();
current_freq = new_freq_ppm * 1.0e-6;
start_adjust();
return current_freq * 1.0e6;
}
/* ================================================== */
static double
read_frequency(void)
{
return current_freq * 1.0e6;
}
/* ================================================== */
static void
get_offset_correction(struct timeval *raw,
double *corr, double *err)
{
stop_adjust();
*corr = -offset_register;
start_adjust();
if (err)
*err = 0.0;
}
/* ================================================== */
void
SYS_MacOSX_Initialise(void)
{
int result;
size_t len;
struct clockinfo clockinfo;
int mib[2];
mib[0] = CTL_KERN;
mib[1] = KERN_CLOCKRATE;
len = sizeof(clockinfo);
result = sysctl(mib, 2, &clockinfo, &len, NULL, 0);
if(result < 0) {
LOG_FATAL(LOGF_SysMacOSX, "Cannot read clockinfo");
}
kern_tickadj = clockinfo.tickadj;
kern_bigadj = clockinfo.tick;
clock_initialise();
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
get_offset_correction,
NULL /* set_leap */,
NULL /* set_sync_status */);
}
/* ================================================== */
void
SYS_MacOSX_Finalise(void)
{
clock_finalise();
}
/* ================================================== */
#endif

View File

@@ -2,36 +2,36 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
*
* Copyright (C) Richard P. Curnow 1997-2001
* Copyright (C) J. Hannken-Illjes 2001
* Copyright (C) Bryan Christianson 2015
*
* 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.
*
*
**********************************************************************
=======================================================================
Deal with broadcast server functions.
Header file for MacOS X driver
*/
#ifndef GOT_BROADCAST_H
#define GOT_BROADCAST_H
#ifndef GOT_SYS_MACOSX_H
#define GOT_SYS_MACOSX_H
#include "addressing.h"
void SYS_MacOSX_Initialise(void);
extern void BRD_Initialise(void);
extern void BRD_Finalise(void);
extern void BRD_AddDestination(IPAddr *addr, unsigned short port, int interval);
#endif /* GOT_BROADCAST_H */
void SYS_MacOSX_Finalise(void);
#endif

View File

@@ -212,7 +212,7 @@ accrue_offset(double offset, double corr_rate)
/* Positive offset means system clock is fast of true time, therefore
step backwards */
static void
static int
apply_step_offset(double offset)
{
struct timeval old_time, new_time, T1;
@@ -226,7 +226,8 @@ apply_step_offset(double offset)
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysNetBSD, "settimeofday() failed");
DEBUG_LOG(LOGF_SysNetBSD, "settimeofday() failed");
return 0;
}
UTI_AddDoubleToTimeval(&T0, offset, &T1);
@@ -234,6 +235,7 @@ apply_step_offset(double offset)
start_adjust();
return 1;
}
/* ================================================== */
@@ -307,7 +309,8 @@ SYS_NetBSD_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
get_offset_correction,
NULL /* set_leap */);
NULL /* set_leap */,
NULL /* set_sync_status */);
}

View File

@@ -219,7 +219,7 @@ accrue_offset(double offset, double corr_rate)
/* Positive offset means system clock is fast of true time, therefore
step backwards */
static void
static int
apply_step_offset(double offset)
{
struct timeval old_time, new_time, rounded_new_time, T1;
@@ -248,7 +248,8 @@ apply_step_offset(double offset)
UTI_DiffTimevalsToDouble(&rounding_error, &rounded_new_time, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysSolaris, "settimeofday() failed");
DEBUG_LOG(LOGF_SysSolaris, "settimeofday() failed");
return 0;
}
UTI_AddDoubleToTimeval(&T0, offset, &T1);
@@ -257,6 +258,8 @@ apply_step_offset(double offset)
offset_register += rounding_error;
start_adjust();
return 1;
}
/* ================================================== */
@@ -426,7 +429,8 @@ SYS_Solaris_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
get_offset_correction,
NULL /* set_leap */);
NULL /* set_leap */,
NULL /* set_sync_status */);
/* Turn off the kernel switch that keeps the system clock in step
with the non-volatile clock */

View File

@@ -223,7 +223,7 @@ accrue_offset(double offset, double corr_rate)
/* Positive offset means system clock is fast of true time, therefore
step backwards */
static void
static int
apply_step_offset(double offset)
{
struct timeval old_time, new_time, T1;
@@ -236,7 +236,8 @@ apply_step_offset(double offset)
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
LOG_FATAL(LOGF_SysSunOS, "settimeofday() failed");
DEBUG_LOG(LOGF_SysSunOS, "settimeofday() failed");
return 0;
}
UTI_AddDoubleToTimeval(&T0, offset, &T1);
@@ -244,6 +245,7 @@ apply_step_offset(double offset)
start_adjust();
return 1;
}
/* ================================================== */
@@ -379,7 +381,8 @@ SYS_SunOS_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
get_offset_correction,
NULL /* set_leap */);
NULL /* set_leap */,
NULL /* set_sync_status */);
/* Turn off the kernel switch that keeps the system clock in step
with the non-volatile clock */

View File

@@ -29,9 +29,9 @@
#ifndef GOT_SYSINCL_H
#define GOT_SYSINCL_H
#if defined (SOLARIS) || defined(SUNOS) || defined(LINUX) || defined(__NetBSD__)
#if defined (SOLARIS) || defined(SUNOS) || defined(LINUX) || defined(__NetBSD__) || defined (MACOSX)
#if !defined(__NetBSD__) && !defined(__FreeBSD__)
#if !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(MACOSX)
#include <alloca.h>
#endif
#include <assert.h>
@@ -39,7 +39,7 @@
#include <errno.h>
#include <fcntl.h>
#include <float.h>
#if !defined(__FreeBSD__)
#if !defined(__FreeBSD__) && !defined(MACOSX)
#include <malloc.h>
#endif
#include <math.h>
@@ -62,9 +62,9 @@
#include <syslog.h>
#include <time.h>
#ifdef HAS_INTTYPES_H
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#elif HAS_STDINT_H
#elif HAVE_STDINT_H
#include <stdint.h>
#else
/* Tough */
@@ -78,7 +78,7 @@
#endif
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
/* For inet_ntop() */
#include <arpa/inet.h>
#endif

View File

@@ -27,6 +27,7 @@
#include "config.h"
#include "array.h"
#include "conf.h"
#include "local.h"
#include "memory.h"
@@ -46,6 +47,37 @@ static char *filename;
static double update_interval;
static double T0, k0, k1, k2;
struct Point {
double temp;
double comp;
};
static ARR_Instance points;
static double
get_tempcomp(double temp)
{
unsigned int i;
struct Point *p1 = NULL, *p2 = NULL;
/* If not configured with points, calculate the compensation from the
specified quadratic function */
if (!points)
return k0 + (temp - T0) * k1 + (temp - T0) * (temp - T0) * k2;
/* Otherwise interpolate/extrapolate between two nearest points */
for (i = 1; i < ARR_GetSize(points); i++) {
p2 = (struct Point *)ARR_GetElement(points, i);
if (p2->temp >= temp)
break;
}
p1 = p2 - 1;
return (temp - p1->temp) / (p2->temp - p1->temp) *
(p2->comp - p1->comp) + p1->comp;
}
static void
read_timeout(void *arg)
{
@@ -55,11 +87,13 @@ read_timeout(void *arg)
f = fopen(filename, "r");
if (f && fscanf(f, "%lf", &temp) == 1) {
comp = k0 + (temp - T0) * k1 + (temp - T0) * (temp - T0) * k2;
comp = get_tempcomp(temp);
if (fabs(comp) <= MAX_COMP) {
comp = LCL_SetTempComp(comp);
DEBUG_LOG(LOGF_TempComp, "tempcomp updated to %f for %f", comp, temp);
if (logfileid != -1) {
struct timeval now;
@@ -83,10 +117,41 @@ read_timeout(void *arg)
timeout_id = SCH_AddTimeoutByDelay(update_interval, read_timeout, NULL);
}
static void
read_points(const char *filename)
{
FILE *f;
char line[256];
struct Point *p;
f = fopen(filename, "r");
if (!f) {
LOG_FATAL(LOGF_TempComp, "Could not open tempcomp point file %s", filename);
return;
}
points = ARR_CreateInstance(sizeof (struct Point));
while (fgets(line, sizeof (line), f)) {
p = (struct Point *)ARR_GetNewElement(points);
if (sscanf(line, "%lf %lf", &p->temp, &p->comp) != 2) {
LOG_FATAL(LOGF_Configure, "Could not read tempcomp point from %s", filename);
break;
}
}
fclose(f);
if (ARR_GetSize(points) < 2)
LOG_FATAL(LOGF_Configure, "Not enough points in %s", filename);
}
void
TMC_Initialise(void)
{
CNF_GetTempComp(&filename, &update_interval, &T0, &k0, &k1, &k2);
char *point_file;
CNF_GetTempComp(&filename, &update_interval, &point_file, &T0, &k0, &k1, &k2);
if (filename == NULL)
return;
@@ -94,6 +159,9 @@ TMC_Initialise(void)
if (update_interval <= 0.0)
update_interval = 1.0;
if (point_file)
read_points(point_file);
logfileid = CNF_GetLogTempComp() ? LOG_FileOpen("tempcomp",
" Date (UTC) Time Temp. Comp.")
: -1;
@@ -107,6 +175,8 @@ TMC_Finalise(void)
if (filename == NULL)
return;
if (points)
ARR_DestroyInstance(points);
SCH_RemoveTimeout(timeout_id);
Free(filename);
}

19
test/compilation/001-features Executable file
View File

@@ -0,0 +1,19 @@
#!/bin/sh
# Try to compile chrony in various combinations of disabled features
cd ../..
for opts in \
"--disable-asyncdns" \
"--disable-rtc" \
"--disable-cmdmon" \
"--disable-ntp" \
"--disable-refclock" \
"--disable-cmdmon --disable-ntp" \
"--disable-cmdmon --disable-refclock" \
"--disable-cmdmon --disable-ntp --disable-refclock"
do
./configure $opts
make || exit 1
done

View File

@@ -0,0 +1,41 @@
#!/bin/bash
. test.common
test_start "source selection"
# Falsetickers should be detected if their number is less than half of all
base_delay=1e-3
servers=5
for falsetickers in 1 2; do
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
done
for falsetickers in 3 4; do
run_test || test_fail
check_chronyd_exit || test_fail
check_packet_interval || test_fail
# These check are expected to fail
check_source_selection && test_fail
check_sync && test_fail
done
# Sources with large asymmetric delay should be excluded
servers=3
falsetickers=0
base_delay="(+ 1e-3 (equal 0.1 to 2) (equal 0.1 to 3))"
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
test_pass

View File

@@ -4,7 +4,7 @@
test_start "reply to client configured as server"
server_conf="server 192.168.123.2
server_conf="server 192.168.123.2 noselect
acquisitionport 123"
client_conf="acquisitionport 123"

View File

@@ -5,17 +5,42 @@ test_start "leap second"
export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Dec 30 2008 0:00:00' +'%s')
leap=$[2 * 24 * 3600]
limit=$[4 * 24 * 3600]
server_conf="refclock SHM 0 dpoll 10 poll 10
leapsectz right/UTC"
server_step="(* 1.0 (equal 0.1 (sum 1.0) $[2 * 24 * 3600 + 1]))"
client_step="(* 1.0 (equal 0.1 (sum 1.0) $[2 * 24 * 3600 + 1]))"
refclock_jitter=1e-9
refclock_offset="(* -1.0 (equal 0.1 (max (sum 1.0) $leap) $leap))"
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
for leapmode in system step slew; do
client_conf="leapsecmode $leapmode"
if [ $leapmode = slew ]; then
max_sync_time=$[$leap + 12]
else
max_sync_time=$[$leap]
fi
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
done
for smoothmode in "" "leaponly"; do
server_conf="refclock SHM 0 dpoll 10 poll 10
leapsectz right/UTC
leapsecmode slew
smoothtime 400 0.001 $smoothmode"
client_conf="leapsecmode system"
min_sync_time=230000
max_sync_time=240000
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
done
test_pass

View File

@@ -3,7 +3,9 @@
. test.common
test_start "presend option"
client_server_options="presend 6"
min_sync_time=140
max_sync_time=260
client_server_options="presend 6 maxdelay 16"
run_test || test_fail
check_chronyd_exit || test_fail

Some files were not shown because too many files have changed in this diff Show More