summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FAQ493
-rw-r--r--INSTALL12
-rw-r--r--Makefile.in21
-rw-r--r--NEWS66
-rw-r--r--README89
-rw-r--r--addrfilt.c40
-rw-r--r--addrfilt.h5
-rw-r--r--array.c129
-rw-r--r--array.h56
-rw-r--r--broadcast.c159
-rw-r--r--candm.h108
-rw-r--r--chrony.171
-rw-r--r--chrony.conf.5.in48
-rw-r--r--chrony.texi.in1074
-rw-r--r--chrony.txt1346
-rw-r--r--chrony_timex.h73
-rw-r--r--chronyc.1.in5
-rw-r--r--chronyd.8.in6
-rw-r--r--client.c257
-rw-r--r--clientlog.c119
-rw-r--r--clientlog.h21
-rw-r--r--cmdmon.c476
-rw-r--r--cmdparse.c131
-rw-r--r--cmdparse.h11
-rw-r--r--conf.c502
-rw-r--r--conf.h12
-rwxr-xr-xconfigure128
-rw-r--r--contrib/DNSchrony/COPYING339
-rwxr-xr-xcontrib/DNSchrony/DNSchrony.pl583
-rwxr-xr-xcontrib/DNSchrony/DNSchronyADD21
-rwxr-xr-xcontrib/DNSchrony/DNSchronyDELETE7
-rwxr-xr-xcontrib/DNSchrony/DNSchronyUPDATE7
-rw-r--r--contrib/DNSchrony/README166
-rw-r--r--contrib/DNSchrony/ip-up.local22
-rw-r--r--examples/chrony.conf.example112
-rw-r--r--examples/chrony.conf.example228
-rw-r--r--examples/chrony.conf.example3 (renamed from examples/chrony.conf.example)26
-rw-r--r--examples/chrony.spec3
-rw-r--r--hash.h2
-rw-r--r--hash_intmd5.c5
-rw-r--r--hash_nss.c14
-rw-r--r--hash_tomcrypt.c5
-rw-r--r--keys.c164
-rw-r--r--keys.h14
-rw-r--r--local.c120
-rw-r--r--local.h22
-rw-r--r--localp.h8
-rw-r--r--logging.c2
-rw-r--r--logging.h5
-rw-r--r--main.c38
-rw-r--r--manual.c26
-rw-r--r--manual.h1
-rw-r--r--memory.c67
-rw-r--r--memory.h14
-rw-r--r--mkdirpp.c7
-rw-r--r--nameserv.c81
-rw-r--r--nameserv.h2
-rw-r--r--nameserv_async.c33
-rw-r--r--nameserv_async.h2
-rw-r--r--ntp.h55
-rw-r--r--ntp_core.c1144
-rw-r--r--ntp_core.h7
-rw-r--r--ntp_io.c227
-rw-r--r--ntp_io.h14
-rw-r--r--ntp_sources.c588
-rw-r--r--ntp_sources.h11
-rw-r--r--pktlength.c62
-rw-r--r--refclock.c126
-rw-r--r--refclock.h2
-rw-r--r--refclock_pps.c2
-rw-r--r--reference.c220
-rw-r--r--reference.h17
-rw-r--r--reports.h20
-rw-r--r--rtc.c6
-rw-r--r--rtc_linux.c19
-rw-r--r--sched.c24
-rw-r--r--smooth.c342
-rw-r--r--smooth.h48
-rw-r--r--sources.c888
-rw-r--r--sources.h33
-rw-r--r--sourcestats.c96
-rw-r--r--sourcestats.h22
-rw-r--r--srcparams.h13
-rw-r--r--stubs.c329
-rw-r--r--sys.c14
-rw-r--r--sys_generic.c52
-rw-r--r--sys_generic.h3
-rw-r--r--sys_linux.c111
-rw-r--r--sys_macosx.c314
-rw-r--r--sys_macosx.h (renamed from broadcast.h)28
-rw-r--r--sys_netbsd.c9
-rw-r--r--sys_solaris.c10
-rw-r--r--sys_sunos.c9
-rw-r--r--sysincl.h12
-rw-r--r--tempcomp.c76
-rwxr-xr-xtest/compilation/001-features19
-rwxr-xr-xtest/simulation/009-sourceselection41
-rwxr-xr-xtest/simulation/111-knownclient2
-rwxr-xr-xtest/simulation/113-leapsecond39
-rwxr-xr-xtest/simulation/114-presend4
-rwxr-xr-xtest/simulation/116-minsources24
-rwxr-xr-xtest/simulation/117-fallbackdrift23
-rwxr-xr-xtest/simulation/118-maxdelay28
-rwxr-xr-xtest/simulation/119-smoothtime68
-rwxr-xr-xtest/simulation/202-prefer21
-rw-r--r--test/simulation/test.common21
-rw-r--r--util.c136
-rw-r--r--util.h9
-rw-r--r--version.txt2
-rw-r--r--wrap_adjtimex.c120
-rw-r--r--wrap_adjtimex.h41
111 files changed, 7009 insertions, 5846 deletions
diff --git a/FAQ b/FAQ
index f683718..14a81be 100644
--- a/FAQ
+++ b/FAQ
@@ -1,332 +1,283 @@
-1 Administrative issues
-=======================
+ Frequently Asked Questions
+ __________________________________________________________________
-1.1 Where can I get chrony source code?
----------------------------------------
+1. Chrony compared to other programs
-Tarballs are available via the 'Download' link on the chrony web site.
-For the current development from the developers' version control system
-see the 'Git' link on the web site.
+ 1.1. How does chrony compare to ntpd?
-1.2 Are there any packaged versions of chrony?
-----------------------------------------------
+ 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 [1]comparison
+ page on the chrony website and section [2]Comparison with ntpd in the
+ manual.
-We are aware of packages for Arch, Debian, Fedora, Gentoo, Mandriva,
-Slackware, Ubuntu, FreeBSD and NetBSD. We are not involved with how
-these are built or distributed.
-
-1.3 Where is the home page?
----------------------------
-
-It is currently at http://chrony.tuxfamily.org
-(http://chrony.tuxfamily.org).
-
-1.4 Is there a mailing list?
-----------------------------
-
-Yes, it's currently at <chrony-users@chrony.tuxfamily.org>. There is a
-low-volume list called chrony-announce which is just for announcements
-of new releases or similar matters of high importance. You can join the
-lists by sending a message with the subject subscribe to
-<chrony-users-request@chrony.tuxfamily.org> or
-<chrony-announce-request@chrony.tuxfamily.org> respectively.
-
- For those who want to contribute to the development of chrony, there
-is a developers' mailing list. You can subscribe by sending mail with
-the subject subscribe to <chrony-dev-request@chrony.tuxfamily.org>.
-
-1.5 What licence is applied to chrony?
---------------------------------------
-
-Starting from version 1.15, chrony is licensed under the GNU General
-Public License, Version 2. Versions prior to 1.15 were licensed under a
-custom BSD-like license.
+ 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.
-2 Chrony compared to other programs
-===================================
+ 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.
+ __________________________________________________________________
+
+2. Configuration issues
+
+ 2.1. 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.
+
+ 2.2. 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.
+
+ 2.3. 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.
+
+ 2.4. 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.
-2.1 How does chrony compare to ntpd?
-------------------------------------
+ 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.
-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 section 'Comparison
-with ntpd' in the manual.
+ 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.
- 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.
+ An example of the directive for an NTP server on the internet that you
+ are allowed to poll frequently could be
- 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.
-
-3 Configuration issues
-======================
-
-3.1 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.
-
-3.2 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.
-
-3.3 How can I make chronyd more secure?
----------------------------------------
-
-If you don't need to serve time to NTP clients, you can add 'port 0' to
-the 'chrony.conf' file to disable the NTP server/peer sockets and
-prevent NTP requests from reaching 'chronyd'.
-
- 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
-
- 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.
-
-3.4 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'.
+ server foo.example.net minpoll 4 maxpoll 6 polltarget 16
- 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 suitable for public NTP
-servers, which normally don't allow too frequent polling, but if you run
-your own NTP servers or have permission to poll the servers frequently,
-setting the options for shorter polling intervals may significantly
-improve the accuracy of the system clock.
-
- The optimal polling interval depends on many factors, this includes
-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 a server
-located in the same LAN could be
+ 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 previous example
+ 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
+ __________________________________________________________________
-4 Computer is not synchronising
-===============================
+3. Computer is not synchronising
-This is the most common problem. There are a number of reasons, see the
-following questions.
+ This is the most common problem. There are a number of reasons, see the
+ following questions.
-4.1 Behind a firewall?
-----------------------
+ 3.1. 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.
+ 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.
-4.2 Do you have a non-permanent (i.e. intermittent) Internet connection?
-------------------------------------------------------------------------
+ 3.2. 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.
+ 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.
+ __________________________________________________________________
-4.3 In measurements.log, do the '7' and '8' flag columns always show zero?
---------------------------------------------------------------------------
+4. Issues with chronyc
-Do you have a 'local stratum X' directive in the 'chrony.conf' file? If
-X is lower than the stratum of the server you're trying to use, this
-situation will arise. You should always make X quite high (e.g. 10) in
-this directive.
+ 4.1. I keep getting the error 506 Cannot talk to daemon
-5 Issues with chronyc
-=====================
+ 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.
-5.1 I keep getting the error '506 Cannot talk to daemon'
---------------------------------------------------------
+ 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).
-Make sure that the 'chrony.conf' file (on the computer where 'chronyd'
-is running) has a 'cmdallow' entry for the computer you are running
-'chronyc' on. This isn't necessary for localhost.
+ 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.
- 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).
+ 4.2. Is the chronyc / chronyd protocol documented anywhere?
- 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.
+ Only by the source code :-) See cmdmon.c (chronyd side) and client.c
+ (chronyc side).
+ __________________________________________________________________
-5.2 Is the chronyc<->chronyd protocol documented anywhere?
-----------------------------------------------------------
+5. Real-time clock issues
-Only by the source code :-) See cmdmon.c ('chronyd' side) and client.c
-('chronyc' side).
+ 5.1. What is the real-time clock (RTC)?
-6 Real-time clock issues
-========================
+ 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.
-6.1 What is the real-time clock (RTC)?
---------------------------------------
+ 5.2. I want to use chronyd's real-time clock support. Must I disable hwclock?
-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.
+ 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.
-6.2 I want to use chronyd's real-time clock support. Must I disable hwclock?
-----------------------------------------------------------------------------
+ There is no need to remove hwclock from the boot process, as long as
+ chronyd is started after it has run.
-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.
+ 5.3. I just keep getting the 513 RTC driver not running message
- There is no need to remove hwclock from the boot process, as long as
-'chronyd' is started after it has run.
+ 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
+ __________________________________________________________________
-6.3 I just keep getting the '513 RTC driver not running' message
-----------------------------------------------------------------
+6. Microsoft Windows
-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
+ 6.1. Does chrony support Windows?
-7 Microsoft 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.
-7.1 Does chrony support Windows?
---------------------------------
+ 6.2. Are there any plans to 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 an
-NT service.
+ We have no plans to do this. Anyone is welcome to pick this work up and
+ contribute it back to the project.
+ __________________________________________________________________
-7.2 Are there any plans to support Windows?
--------------------------------------------
+7. NTP-specific issues
-We have no plans to do this. Anyone is welcome to pick this work up and
-contribute it back to the project.
+ 7.1. Can chrony be driven from broadcast NTP servers?
-8 NTP-specific issues
-=====================
+ No, this NTP mode is not implemented yet.
-8.1 Can chrony be driven from broadcast NTP servers?
-----------------------------------------------------
+ 7.2. Can chronyd transmit broadcast NTP packets (e.g. to synchronise other
+ computers on a private LAN)?
-No, this NTP mode is not implemented yet.
+ Yes. Starting from version 1.17, chrony has this capability.
-8.2 Can chronyd transmit broadcast NTP packets (e.g. to synchronise other computers on a private LAN)?
-------------------------------------------------------------------------------------------------------
+ 7.3. Can chrony keep the system clock a fixed offset away from real time?
-Yes. Starting from version 1.17, chrony has this capability.
+ This is not possible as the program currently stands.
-8.3 Can chrony keep the system clock a fixed offset away from real time?
-------------------------------------------------------------------------
+ 7.4. What happens if the network connection is dropped without using chronyc's
+ offline command first?
-This is not possible as the program currently stands.
+ 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.
-8.4 What happens if the network connection is dropped without using chronyc's 'offline' command first?
-------------------------------------------------------------------------------------------------------
+ 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.
+ __________________________________________________________________
-In this case 'chronyd' will keep trying to access the server(s) that it
-thinks are online. Eventually it will decide that they are unreachable
-and no longer consider itself synchronised to them. If you have other
-computers on your LAN accessing the computer that is affected this way,
-they too will become 'unsynchronised', unless you have the 'local'
-directive set up on the master computer.
+8. Linux-specific issues
- The 'auto_offline' option to the 'server' entry in the chrony.conf
-file may be useful to avoid this situation.
+ 8.1. I get Could not open /dev/rtc, Device or resource busy in my syslog file
-9 Linux-specific issues
-=======================
+ Some other program running on the system may be using the device.
+ __________________________________________________________________
-9.1 I get "Could not open /dev/rtc, Device or resource busy" in my syslog file
-------------------------------------------------------------------------------
+9. Solaris-specific issues
-Some other program running on the system may be using the device.
+ 9.1. I get an error message about not being able to open kvm to change
+ dosynctodr
-10 Solaris-specific issues
-==========================
+ (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.
+ __________________________________________________________________
-10.1 On Solaris 2.8, I get an error message about not being able to open kvm to change dosynctodr
--------------------------------------------------------------------------------------------------
+ Last updated 2015-06-23 16:02:17 CEST
-(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.
+References
+ 1. http://chrony.tuxfamily.org/comparison.html
+ 2. http://chrony.tuxfamily.org/manual.html#Comparison-with-ntpd
diff --git a/INSTALL b/INSTALL
index b9cb36f..68685b8 100644
--- a/INSTALL
+++ b/INSTALL
@@ -82,14 +82,14 @@ location of the file called 'dir'. This will typically be
Now that the software is successfully installed, the next step is to
set up a configuration file. The default location of the file is
-'/etc/chrony.conf'. Suppose you want to use public NTP servers from the
-pool.ntp.org project as your time reference. A minimal useful
-configuration file could be
+'/etc/chrony.conf'. Several examples of configuration with comments are
+included in the examples directory. Suppose you want to use public NTP
+servers from the pool.ntp.org project as your time reference. A minimal
+useful configuration file could be
- server 0.pool.ntp.org iburst
- server 1.pool.ntp.org iburst
- server 2.pool.ntp.org iburst
+ pool pool.ntp.org iburst
makestep 10 3
+ rtcsync
Then, 'chronyd' can be run.
diff --git a/Makefile.in b/Makefile.in
index 2bcf5e8..a031ba3 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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
diff --git a/NEWS b/NEWS
index 5e958e5..140fa58 100644
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,74 @@
+New in version 2.1.1
+====================
+
+Bug fixes
+---------
+* Fix clock stepping by integer number of seconds on Linux
+
+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-1799)
+ (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)
diff --git a/README b/README
index b6b2de5..3905c55 100644
--- a/README
+++ b/README
@@ -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.
-
-chronyd is a (background) daemon program that can be started at boot
-time. This does most of the work.
-
-chronyc is a command-line interface program which can be used to
-monitor chronyd's performance and to change various operating
-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.
-
+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.
+
+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.
+
+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.
diff --git a/addrfilt.c b/addrfilt.c
index 4b8879a..c998b0c 100644
--- a/addrfilt.c
+++ b/addrfilt.c
@@ -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
@@ -366,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)
diff --git a/addrfilt.h b/addrfilt.h
index 65784e5..b8c131f 100644
--- a/addrfilt.h
+++ b/addrfilt.h
@@ -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 */
diff --git a/array.c b/array.c
new file mode 100644
index 0000000..26a3160
--- /dev/null
+++ b/array.c
@@ -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;
+}
diff --git a/array.h b/array.h
new file mode 100644
index 0000000..c812e84
--- /dev/null
+++ b/array.h
@@ -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
diff --git a/broadcast.c b/broadcast.c
deleted file mode 100644
index e499621..0000000
--- a/broadcast.c
+++ /dev/null
@@ -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;
-
-}
-
-
diff --git a/candm.h b/candm.h
index f3eb433..f3bea3a 100644
--- a/candm.h
+++ b/candm.h
@@ -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) */
@@ -116,6 +119,10 @@ typedef struct {
transmitted for each packet type. */
typedef struct {
+ int32_t EOR;
+} REQ_Null;
+
+typedef struct {
IPAddr mask;
IPAddr address;
int32_t EOR;
@@ -188,6 +195,12 @@ typedef struct {
} REQ_Modify_Maxupdateskew;
typedef struct {
+ int32_t limit;
+ Float threshold;
+ int32_t EOR;
+} REQ_Modify_Makestep;
+
+typedef struct {
Timeval ts;
int32_t EOR;
} REQ_Logon;
@@ -209,19 +222,11 @@ typedef struct {
} 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;
int32_t EOR;
@@ -258,10 +263,6 @@ typedef struct {
} REQ_Del_Source;
typedef struct {
- int32_t EOR;
-} REQ_WriteRtc;
-
-typedef struct {
Float dfreq;
int32_t EOR;
} REQ_Dfreq;
@@ -273,31 +274,10 @@ typedef struct {
} 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
@@ -309,30 +289,22 @@ typedef struct {
} REQ_ClientAccessesByIndex;
typedef struct {
- int32_t EOR;
-} REQ_ManualList;
-
-typedef struct {
int32_t index;
int32_t EOR;
} REQ_ManualDelete;
typedef struct {
+ Float distance;
int32_t EOR;
-} REQ_MakeStep;
-
-typedef struct {
- int32_t EOR;
-} REQ_Activity;
+} REQ_ReselectDistance;
-typedef struct {
- int32_t EOR;
-} REQ_Reselect;
+#define REQ_SMOOTHTIME_RESET 0
+#define REQ_SMOOTHTIME_ACTIVATE 1
typedef struct {
- Float distance;
+ int32_t option;
int32_t EOR;
-} REQ_ReselectDistance;
+} REQ_SmoothTime;
/* ================================================== */
@@ -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
@@ -582,12 +548,6 @@ typedef struct {
typedef struct {
IPAddr ip;
- uint32_t bits_specd;
- uint32_t bitmap[8];
-} RPY_SubnetsAccessed_Subnet;
-
-typedef struct {
- IPAddr ip;
uint32_t client_hits;
uint32_t peer_hits;
uint32_t cmd_hits_auth;
@@ -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
diff --git a/chrony.1 b/chrony.1
deleted file mode 100644
index 5dd2938..0000000
--- a/chrony.1
+++ /dev/null
@@ -1,71 +0,0 @@
-.TH CHRONY 1 "April 2015" "chrony 1.31.1" "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.
-
diff --git a/chrony.conf.5.in b/chrony.conf.5.in
index 7bb5809..44ab753 100644
--- a/chrony.conf.5.in
+++ b/chrony.conf.5.in
@@ -1,4 +1,4 @@
-.TH chrony.conf 5 "April 2015" "chrony 1.31.1" "Configuration Files"
+.TH chrony.conf 5 "June 2015" "chrony 2.1.1" "Configuration Files"
.SH NAME
chrony.conf \- chronyd configuration 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
-
- server a.b.c iburst
- server d.e.f iburst
- server g.h.i iburst
- keyfile @SYSCONFDIR@/chrony.keys
- generatecommandkey
+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
+
+.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)
diff --git a/chrony.texi.in b/chrony.texi.in
index 480b553..908ab95 100644
--- a/chrony.texi.in
+++ b/chrony.texi.in
@@ -24,7 +24,7 @@
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1997-1999 Richard P. Curnow
-Copyright @copyright{} 2009-2014 Miroslav Lichvar
+Copyright @copyright{} 2009-2015 Miroslav Lichvar
@end titlepage
@c }}}
@c {{{ Top node
@@ -35,7 +35,6 @@ Copyright @copyright{} 2009-2014 Miroslav Lichvar
* Installation:: How to compile and install the software
* Typical scenarios:: How to configure the software for some common cases
* Usage reference:: Reference manual
-* FAQ:: Answers to some common questions about chrony
* GPL:: The GNU General Public License
@end menu
@c }}}
@@ -56,34 +55,30 @@ Copyright @copyright{} 2009-2014 Miroslav Lichvar
@c {{{ S:Overview
@node Overview
@section Overview
-Chrony is a software package for maintaining the accuracy of computer
-system clocks. It consists of a pair of programs :
-
-@itemize @bullet
-@item @code{chronyd}. This is a daemon which runs in background on the
-system. It obtains measurements (e.g. via the network) of the system's
-offset relative to other systems, and adjusts the system time
-accordingly. For isolated systems, the user can periodically enter the
-correct time by hand (using @code{chronyc}). In either case,
-@code{chronyd} determines the rate at which the computer gains or loses
-time, and compensates for this.
-
-@code{chronyd} can also act as an NTP server, and provide a time-of-day service
-to other computers. A typical set-up is to run @code{chronyd} on a gateway
-computer that has a dial-up link to the Internet, and use it to serve time to
-computers on a private LAN sitting behind the gateway. The IP addresses that
-can act as clients of @code{chronyd} can be tightly controlled. The default is
-no client access.
-
-@item @code{chronyc}. This is a command-line driven control and
-monitoring program. An administrator can use this to fine-tune various
-parameters within the daemon, add or delete servers etc whilst the
-daemon is running.
+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.
+
+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.
+
+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, @code{chronyd} is a daemon that can
+be started at boot time and @code{chronyc} is a command-line interface
+program which can be used to monitor @code{chronyd}'s performance and to
+change various operating parameters whilst it is running.
The IP addresses from which @code{chronyc} clients may connect can be tightly
controlled. The default is just the computer that @code{chronyd} itself is
running on.
-@end itemize
@c }}}
@c {{{ S:Acknowledgments
@node Acknowledgements
@@ -94,10 +89,9 @@ Data Security, Inc. MD5 Message-Digest Algorithm} for authenticating
messages between different machines on the network.
In writing the @code{chronyd} program, extensive use has been made of
-RFC1305, written by David Mills. The @code{ntp} suite's source code has
-been occasionally used to check details of the protocol that the RFC did
-not make absolutely clear. The core algorithms in @code{chronyd} are
-all completely distinct from @code{ntp}, however.
+RFC 1305 and RFC 5905, written by David Mills. The source code of
+the NTP reference implementation has been used to check details of the
+protocol.
@c }}}
@c {{{ S:Availability
@node Availability
@@ -124,24 +118,10 @@ different operating systems may provide different function calls to
achieve this, and even where the same function is used it may have
different quirks in its behaviour.
-The software is known to work in the following environments:
-@itemize @bullet
-@item Linux 2.2 and newer
-
-@item NetBSD
-@item BSD/386
-
-@item Solaris 2.3/2.5/2.5.1/2.6/2.7/2.8 on Sparc (Sparc 20, Ultrasparc) and
-i386
-
-@item SunOS 4.1.4 on Sparc 2 and Sparc20.
-@end itemize
-
-Closely related systems may work too, but they have not been tested.
-
-Porting the software to other system (particularly to those supporting
-an @code{adjtime} system call) should not be difficult, however it
-requires access to such systems to test out the driver.
+The software is known to work on Linux, FreeBSD, NetBSD, Mac OS X and Solaris.
+Closely related systems may work too. Porting the software to other systems
+(particularly to those supporting an @code{adjtime} system call) should not be
+difficult, however it requires access to such systems to test out the driver.
@c }}}
@c {{{ S:Other programs
@node Other time synchronisation packages
@@ -211,11 +191,10 @@ Things @code{ntpd} can do that @code{chronyd} can't:
@itemize @bullet
@item
-@code{ntpd} fully supports NTP version 4 (RFC5905), including broadcast,
-multicast, manycast clients / servers and the orphan mode. It also
-supports extra authentication schemes based on public-key cryptography
-(RFC5906). @code{chronyd} uses NTP version 3 (RFC1305), which is
-compatible with version 4.
+@code{ntpd} supports all operating modes from RFC 5905, including
+broadcast, multicast and manycast client / server. It supports the
+orphan mode and it also supports authentication based on public-key
+cryptography described in RFC 5906.
@item
@code{ntpd} has been ported to more types of computer / operating
@@ -307,8 +286,7 @@ Particular areas that need addressing are :
@item Porting to other Unices
This involves creating equivalents of sys_solaris.c, sys_linux.c etc for the
-new system. Note, the Linux driver has been reported as working on a range of
-different architectures (Alpha, Sparc, MIPS as well as x86 of course).
+new system.
@item Porting to Windows NT
@@ -432,15 +410,15 @@ install-info /usr/local/share/info/chrony.info /usr/share/info/dir
Now that the software is successfully installed, the next step is to
set up a configuration file. The default location of the file
-is @file{@SYSCONFDIR@/chrony.conf}. Suppose you want to use public NTP
-servers from the pool.ntp.org project as your time reference. A
+is @file{@SYSCONFDIR@/chrony.conf}. Several examples of configuration with
+comments are included in the examples directory. Suppose you want to use
+public NTP servers from the pool.ntp.org project as your time reference. A
minimal useful configuration file could be
@example
-server 0.pool.ntp.org iburst
-server 1.pool.ntp.org iburst
-server 2.pool.ntp.org iburst
+pool pool.ntp.org iburst
makestep 10 3
+rtcsync
@end example
Then, @code{chronyd} can be run.
@@ -575,28 +553,41 @@ use their facilities.
Assuming that you have found some servers, you need to set up a
configuration file to run chrony. The (compiled-in) default location
-for this file is @file{@SYSCONFDIR@/chrony.conf}. Assuming that your ntp
-servers are called @code{a.b.c} and @code{d.e.f}, your
-@file{chrony.conf} file could contain as a minimum
+for this file is @file{@SYSCONFDIR@/chrony.conf}. Assuming that your NTP
+servers are called @code{foo.example.net}, @code{bar.example.net} and
+@code{baz.example.net}, your @file{chrony.conf} file could contain as a minimum
@example
-server a.b.c
-server d.e.f
-server g.h.i
+server foo.example.net
+server bar.example.net
+server baz.example.net
@end example
However, you will probably want to include some of the other directives
-described later. The @code{driftfile} and @code{makestep} directives may be
-particularly useful. Also, the @code{iburst} server option is useful to speed
-up the initial synchronization. The smallest useful configuration file would
-look something like
+described later. The following directives may be particularly useful :
+@code{driftfile}, @code{makestep}, @code{rtcsync}. Also, the @code{iburst}
+server option is useful to speed up the initial synchronization. The smallest
+useful configuration file would look something like
+
+@example
+server foo.example.net iburst
+server bar.example.net iburst
+server baz.example.net iburst
+driftfile @CHRONYVARDIR@/drift
+makestep 10 3
+rtcsync
+@end example
+
+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 @code{pool}
+directive instead of multiple @code{server} directives. The configuration file
+could in this case look like
@example
-server a.b.c iburst
-server d.e.f iburst
-server g.h.i iburst
+pool pool.ntp.org iburst
driftfile @CHRONYVARDIR@/drift
makestep 10 3
+rtcsync
@end example
@c }}}
@c {{{ S:Infrequent connection
@@ -620,14 +611,14 @@ In this case, you will need some additional configuration to tell
This saves the program from continuously trying to poll the servers when
they are inaccessible.
-Again, assuming that your ntp servers are called @code{a.b.c} and
-@code{d.e.f}, your @file{chrony.conf} file would need to contain
-something like
+Again, assuming that your NTP servers are called @code{foo.example.net},
+@code{bar.example.net} and @code{baz.example.net}, your @file{chrony.conf} file
+would need to contain something like
@example
-server a.b.c
-server d.e.f
-server g.h.i
+server foo.example.net
+server bar.example.net
+server baz.example.net
@end example
However, your computer will keep trying to contact the servers to obtain
@@ -639,9 +630,9 @@ For this reason, it would be better to specify this part of your
configuration file in the following way:
@example
-server a.b.c offline
-server d.e.f offline
-server g.h.i offline
+server foo.example.net offline
+server bar.example.net offline
+server baz.example.net offline
@end example
The @code{offline} keyword indicates that the servers start
@@ -658,9 +649,9 @@ automatically on the first @code{chronyd} start.
The smallest useful configuration file would look something like
@example
-server a.b.c offline
-server d.e.f offline
-server g.h.i offline
+server foo.example.net offline
+server bar.example.net offline
+server baz.example.net offline
keyfile @SYSCONFDIR@/chrony.keys
generatecommandkey
driftfile @CHRONYVARDIR@/drift
@@ -873,9 +864,9 @@ For the @file{@SYSCONFDIR@/chrony.conf} file, the following can be used as an
example.
@example
-server 0.pool.ntp.org maxdelay 0.4 offline
-server 1.pool.ntp.org maxdelay 0.4 offline
-server 2.pool.ntp.org maxdelay 0.4 offline
+server foo.example.net maxdelay 0.4 offline
+server bar.example.net maxdelay 0.4 offline
+server baz.example.net maxdelay 0.4 offline
logdir /var/log/chrony
log statistics measurements tracking
driftfile @CHRONYVARDIR@/drift
@@ -1000,9 +991,8 @@ configuration file. This option is useful if you want to stop and
restart @code{chronyd} 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 @code{chronyd'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.
+The only version where this happens so far is Linux. On other systems
+this option should not be used.
@item -R
When this option is used, the @code{initstepslew} directive and the
@code{makestep} directive used with a positive limit will be ignored.
@@ -1146,6 +1136,7 @@ the configuration file is ignored.
* include directive:: Include a configuration file
* initstepslew directive:: Trim the system clock on boot-up
* keyfile directive:: Specify location of file containing keys
+* leapsecmode directive:: Select leap second handling mode
* leapsectz directive:: Read leap second data from tz database
* local directive:: Allow unsynchronised machine to act as server
* lock_all directive:: Require that chronyd be locked into RAM
@@ -1162,9 +1153,11 @@ the configuration file is ignored.
* maxslewrate directive:: Set maximum slew rate
* maxupdateskew directive:: Stop bad estimates upsetting machine clock
* minsamples directive:: Set minimum number of samples per source
+* minsources directive:: Set minimum number of selectable sources to update clock
* noclientlog directive:: Prevent chronyd from gathering data about clients
* peer directive:: Specify an NTP peer
* pidfile directive:: Specify the file where chronyd's pid is written
+* pool directive:: Specify an NTP pool
* port directive:: Set NTP server port
* refclock directive:: Specify a reference clock
* reselectdist directive:: Set improvement in distance needed to reselect a source
@@ -1175,6 +1168,7 @@ the configuration file is ignored.
* rtcsync directive:: Specify that RTC should be automatically synchronised by kernel
* sched_priority directive:: Require real-time scheduling and specify a priority for it
* server directive:: Specify an NTP server
+* smoothtime directive:: Smooth served time to keep clients close together
* stratumweight directive:: Specify how important is stratum when selecting source
* tempcomp directive:: Specify temperature sensor and compensation coefficients
* user directive:: Specify user for dropping root privileges
@@ -1231,7 +1225,7 @@ to other clients.
Examples of use of the command are as follows:
@example
-allow foo.bar.com
+allow foo.example.net
allow 1.2
allow 3.4.5
allow 6.7.8/22
@@ -1316,47 +1310,32 @@ bindaddress 192.168.1.1
to the configuration file.
-This directive affects NTP (UDP port 123 by default) packets. If no
-@code{bindcmdaddress} directive is present, the address supplied by
-@code{bindaddress} will be used to control binding of the command socket (UDP
-port 323 by default) as well.
-
-The @code{bindaddress} directive has been found to cause problems when used on
-computers that need to pass NTP traffic over multiple network interfaces (e.g.
-firewalls). It is, therefore, not particularly useful. Use of the
-@code{allow} and @code{deny} directives together with a network firewall is
-more likely to be successful.
-
-For each of IPv4 and IPv6 protocols, only one @code{bindaddress}
-directive can be specified.
+For each of IPv4 and IPv6 protocols, only one @code{bindaddress} directive can
+be specified. Therefore, it's not useful on computers which should serve NTP
+on multiple network interfaces.
@c }}}
@c {{{ bindcmdaddress
@node bindcmdaddress directive
@subsection bindcmdaddress
-The @code{bindcmdaddress} directive allows you to restrict the network
+The @code{bindcmdaddress} directive allows you to specify the network
interface to which @code{chronyd} will listen for command packets (issued by
@code{chronyc}). This provides an additional level of access restriction above
that available through @code{cmddeny} mechanism.
-Suppose you want to block all access except from localhost. You
-could add the lines
+By default, @code{chronyd} binds to the loopback interface (with addresses
+@code{127.0.0.1} and @code{::1}). This blocks all access except from
+localhost. To listen for command packets on all interfaces, you can add the
+lines
@example
-bindcmdaddress 127.0.0.1
-bindcmdaddress ::1
+bindcmdaddress 0.0.0.0
+bindcmdaddress ::
@end example
to the configuration file.
For each of IPv4 and IPv6 protocols, only one @code{bindcmdaddress}
directive can be specified.
-
-The default values are set by the @code{bindaddress} directive.
-
-The @code{bindcmdaddress} directive has been found to cause problems when used
-on computers that need to pass command traffic over multiple network
-interfaces. Use of the @code{cmdallow} and @code{cmddeny} directives together
-with a network firewall is more likely to be successful.
@c }}}
@c {{{ broadcast directive
@node broadcast directive
@@ -1424,6 +1403,10 @@ The syntax is identical to the @code{allow} directive.
There is also a @code{cmdallow all} directive with similar behaviour to the
@code{allow all} directive (but applying to control access in this case, of
course).
+
+Note that @code{chronyd} has to be configured with the @code{bindcmdaddress}
+directive to not listen only on the loopback interface to actually allow remote
+access.
@c }}}
@c {{{ cmddeny
@node cmddeny directive
@@ -1633,14 +1616,13 @@ the program exits. (See the dumpdir command above).
@subsection fallbackdrift
Fallback drifts are long-term averages of the system clock drift
calculated over exponentially increasing intervals. They are used
-when the clock is unsynchronised to avoid quickly drifting away from
-true time if there was a short-term deviation in drift before the
-synchronisation was lost.
+when the clock is no longer synchronised to avoid quickly drifting
+away from true time if there was a short-term deviation in the drift
+before the synchronisation was lost.
-The directive specifies the minimum and maximum interval for how long
-the system clock has to be unsynchronised to switch between fallback
-drifts. They are defined as a power of 2 (in seconds). The syntax is
-as follows
+The directive specifies the minimum and maximum interval since last
+clock update to switch between fallback drifts. They are defined as a
+power of 2 (in seconds). The syntax is as follows
@example
fallbackdrift 16 19
@@ -1648,13 +1630,13 @@ fallbackdrift 16 19
In this example, the minimum interval is 16 (18 hours) and maximum
interval is 19 (6 days). The system clock frequency will be set to
-the first fallback 18 hours after the synchronisation was lost, to the
+the first fallback 18 hours after last clock update, to the
second after 36 hours, etc. This might be a good setting to cover
daily and weekly temperature fluctuations.
By default (or if the specified maximum or minimum is 0), no fallbacks
-will be used and the clock frequency will stay at the last value
-calculated before synchronisation was lost.
+are used and the clock frequency changes only with new measurements from
+NTP, reference clocks or manual input.
@c }}}
@c {{{ generatecommandkey
@node generatecommandkey directive
@@ -1722,7 +1704,7 @@ used instead. This makes it easier to restart @code{chronyd} whilst the
system is in normal operation.
The @code{initstepslew} directive takes a threshold and a list of NTP
-servers as arguments. A maximum of 8 will be used. Each of the servers
+servers as arguments. Each of the servers
is rapidly polled several times, and a majority voting mechanism used to
find the most likely range of system clock error that is present. A
step (or slew) is applied to the system clock to correct this error.
@@ -1731,7 +1713,7 @@ step (or slew) is applied to the system clock to correct this error.
An example of use of the command is
@example
-initstepslew 30 foo.bar.com baz.quz.com
+initstepslew 30 foo.example.net bar.example.net
@end example
where 2 NTP servers are used to make the measurement. The @code{30}
@@ -1805,6 +1787,87 @@ The ID for the chronyc authentication key is specified with the commandkey
command (see earlier). The command key can be generated automatically on
start with the @code{generatecommandkey} directive.
@c }}}
+@c {{{ leapsecmode
+@node leapsecmode directive
+@subsection leapsecmode
+A leap second is an adjustment that is occasionally applied to UTC to keep it
+close to the mean solar time. When a leap second is inserted, the last day of
+June or December has an extra second 23:59:60.
+
+For computer clocks that is a problem. The Unix time is defined as number of
+seconds since 00:00:00 UTC on 1 January 1970 without leap seconds. The system
+clock cannot have time 23:59:60, every minute has 60 seconds and every day has
+86400 seconds by definition. The inserted leap second is skipped and the clock
+is suddenly ahead of UTC by one second. The @code{leapsecmode} directive
+selects how that error is corrected. There are four options:
+
+@table @code
+@item system
+When inserting a leap second, the kernel steps the system clock backwards by
+one second when the clock gets to 00:00:00 UTC. When deleting a leap second,
+it steps forward by one second when the clock gets to 23:59:59 UTC. This is
+the default mode when the system driver supports leap seconds (currently Linux
+only).
+@item step
+This is similar to the @code{system} mode, except the clock is stepped by
+@code{chronyd} instead of the kernel. It can be useful to avoid bugs in the
+kernel code that would be executed in the @code{system} mode. This is the
+default mode when the system driver doesn't support leap seconds.
+@item slew
+The clock is corrected by slewing started at 00:00:00 UTC when a leap second is
+inserted or 23:59:59 UTC when a leap second is deleted. This may be preferred
+over the @code{system} and @code{step} modes when applications running on the
+system are sensitive to jumps in the system time and it's acceptable that the
+clock will be off for a longer time. On Linux with the default
+@code{maxslewrate} value (@pxref{maxslewrate directive}) the correction takes
+12 seconds.
+@item ignore
+No correction is applied to the clock for the leap second. The clock will be
+corrected later in normal operation when new measurements are made and the
+estimated offset includes the one second error.
+@end table
+
+An example of the command is
+
+@example
+leapsecmode slew
+@end example
+
+When serving time to NTP clients that can't be configured to correct their
+clocks for a leap second by slewing or they would correct them at slightly
+different rates when it's necessary to keep them close together, the
+@code{slew} mode can be combined with the @code{smoothtime} directive
+(@pxref{smoothtime directive}) to enable a server leap smear.
+
+When smearing a leap second, the leap status is suppressed on the server and
+the served time is corrected slowly be slewing instead of stepping. The clients
+don't need any special configuration as they don't know there is any leap
+second and they follow the server time which eventually brings them back to
+UTC. Care must be taken to ensure they use for synchronization only NTP
+servers which smear the leap second in exactly the same way.
+
+This feature needs to be used carefully, because the server is intentionally
+not serving its best estimate of the true time.
+
+A recommended configuration to enable a server leap smear is:
+
+@example
+leapsecmode slew
+maxslewrate 1000
+smoothtime 400 0.001 leaponly
+@end example
+
+The first directive is necessary to disable the clock step which would reset
+the smoothing process. The second directive limits the slewing rate of the
+local clock to 1000 ppm, which improves the stability of the smoothing process
+when the local correction starts and ends. The third directive enables the
+server time smoothing process. It will start when the clock gets to 00:00:00
+UTC and it will take 17 hours 34 minutes to finish. The frequency offset will
+be changing by 0.001 ppm per second and will reach maximum of 31.623 ppm. The
+@code{leaponly} option makes the duration of the leap smear constant and allows
+the clients to safely synchronise with multiple identically configured leap
+smearing servers.
+@c }}}
@c {{{ leapsectz
@node leapsectz directive
@subsection leapsectz
@@ -1935,7 +1998,7 @@ An example line (which actually appears as a single line in the file)
from the measurements log file is shown below.
@example
-2010-12-22 05:40:50 158.152.1.76 N 8 1111 111 1111 10 10 1.0 \
+2014-10-13 05:40:50 158.152.1.76 N 2 111 111 1111 10 10 1.0 \
-4.966e-03 2.296e-01 1.577e-05 1.615e-01 7.446e-03
@end example
@@ -1944,7 +2007,7 @@ values from the example line above) :
@enumerate 1
@item
-Date [2010-12-22]
+Date [2014-10-13]
@item
Hour:Minute:Second [05:40:50]. Note that the date/time pair is
expressed in UTC, not the local time zone.
@@ -1958,12 +2021,13 @@ currently synchronised.) [N]
@item
Stratum of remote computer. [2]
@item
-RFC1305 tests 1 through 4 (1=pass, 0=fail) [1111]
+RFC 5905 tests 1 through 3 (1=pass, 0=fail) [111]
@item
-Tests for maximum delay, maximum delay ratio and maximum delay dev ratio,
-against defined parameters (1=pass, 0=fail) [111]
+RFC 5905 tests 5 through 7 (1=pass, 0=fail) [111]
@item
-RFC1305 tests 5 through 8 (1=pass, 0=fail) [1111]
+Tests for maximum delay, maximum delay ratio and maximum delay dev ratio,
+against defined parameters, and a test for synchronisation loop
+(1=pass, 0=fail) [1111]
@item
Local poll [10]
@item
@@ -1973,15 +2037,16 @@ Remote poll [10]
to increase or decrease the polling level. This is adjusted based on number
of measurements currently being used for the regression algorithm). [1.0]
@item
-The estimated local clock error (`theta' in RFC1305). Positive indicates that the local clock is slow. [-4.966e-03].
+The estimated local clock error (`theta' in RFC 5905). Positive
+indicates that the local clock is slow of the remote source. [-4.966e-03].
@item
-The peer delay (`delta' in RFC1305). [2.296e-01]
+The peer delay (`delta' in RFC 5905). [2.296e-01]
@item
-The peer dispersion (`epsilon' in RFC1305). [1.577e-05]
+The peer dispersion (`epsilon' in RFC 5905). [1.577e-05]
@item
-The root delay (`Delta' in RFC1305). [1.615e-01]
+The root delay (`DELTA' in RFC 5905). [1.615e-01]
@item
-The root dispersion (`E' in RFC1305). [7.446e-03]
+The root dispersion (`EPSILON' in RFC 5905). [7.446e-03]
@end enumerate
A banner is periodically written to the log file to indicate the
@@ -2373,9 +2438,11 @@ crystal oscillator.
@c {{{ maxsamples
@node maxsamples directive
@subsection maxsamples
-The @code{maxsamples} directive sets the maximum number of samples
-@code{chronyd} should keep for each source. The default is 0, which
-disables the configurable limit, and the useful range is 4 to 64.
+The @code{maxsamples} directive sets the default maximum number of samples
+@code{chronyd} should keep for each source. This setting can be overriden for
+individual sources in the @code{server} and @code{refclock} directives
+(@pxref{server directive}, @pxref{refclock directive}). The default value is
+0, which disables the configurable limit. The useful range is 4 to 64.
The syntax is
@@ -2437,9 +2504,11 @@ the new master estimate.
@c {{{ minsamples
@node minsamples directive
@subsection minsamples
-The @code{minsamples} directive sets the minimum number of samples
-@code{chronyd} should try to keep for each source. The default is 0 and the
-useful range is 4 to 64.
+The @code{minsamples} directive sets the default minimum number of samples
+@code{chronyd} should keep for each source. This setting can be overriden for
+individual sources in the @code{server} and @code{refclock} directives
+(@pxref{server directive}, @pxref{refclock directive}). The default value is
+0. The useful range is 4 to 64.
The syntax is
@@ -2447,6 +2516,23 @@ The syntax is
minsamples <samples>
@end example
@c }}}
+@c {{{ minsources
+@node minsources directive
+@subsection minsources
+The @code{minsources} directive sets the minimum number of sources that need
+to be considered as selectable in the source selection algorithm before the
+local clock is updated. The default value is 1.
+
+Setting this option to a larger number can be used to improve the reliability.
+More sources will have to agree with each other and the clock will not be
+updated when only one source (which could be serving wrong time) is reachable.
+
+The syntax is
+
+@example
+minsources <sources>
+@end example
+@c }}}
@c {{{ noclientlog
@node noclientlog directive
@subsection noclientlog
@@ -2460,6 +2546,21 @@ be reported using the @code{clients} command in @code{chronyc}.
The syntax of this directive is identical to that for the @code{server}
directive (@pxref{server directive}), except that it is used to specify
an NTP peer rather than an NTP server.
+
+Please note that NTP peers that are not configured with a key to enable
+authentication are vulnerable to a denial-of-service attack. An attacker
+knowing that NTP hosts A and B are peering with each other 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.
+
+This attack can be prevented by enabling authentication with the key option, or
+using the @code{server} directive on both sides to specify the other host as a
+server instead of peer, the only drawback is that it will double the network
+traffic between the two hosts.
@c }}}
@c {{{ pidfile
@node pidfile directive
@@ -2470,14 +2571,42 @@ chronyd always writes its process ID (pid) to a file, and checks this file on st
pidfile /var/tmp/chronyd.pid
@end example
@c }}}
+@c {{{ pool
+@node pool directive
+@subsection pool
+The syntax of this directive is similar to that for the @code{server}
+directive (@pxref{server directive}), except that it is used to specify a pool
+of NTP servers rather than a single NTP server. The pool name is expected to
+resolve to multiple addresses which may change over time.
+
+All options valid in the @code{server} directive can be used in this directive
+too. There is one option specific to @code{pool} directive: @code{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, @code{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 @code{maxsources}, the other
+sources will be removed. When a pool source is unreachable or marked as
+falseticker, @code{chronyd} will try to replace the source with a newly
+resolved address of the pool.
+
+An example of the pool directive is
+
+@example
+pool pool.ntp.org iburst maxsources 3
+@end example
+@c }}}
@c {{{ port
@node port directive
@subsection port
This option allows you to configure the port on which @code{chronyd}
-will listen for NTP requests.
+will listen for NTP requests. The port will be open only when an address is
+allowed by the @code{allow} directive or command, an NTP peer is configured, or
+the broadcast server mode is enabled.
The compiled in default is udp/123, the standard NTP port. If set to 0,
-@code{chronyd} will not open the server socket and will operate strictly in a
+@code{chronyd} will never open the server port and will operate strictly in a
client-only mode. The source port used in NTP client requests can be set by
the @code{acquisitionport} directive.
@@ -2624,6 +2753,12 @@ Prefer this source over sources without prefer option.
@item noselect
Never select this source. This is useful for monitoring or with sources
which are not very accurate, but are locked with a PPS refclock.
+@item minsamples
+Set the minimum number of samples kept for this source. This overrides the
+@code{minsamples} directive (@pxref{minsamples directive}).
+@item maxsamples
+Set the maximum number of samples kept for this source. This overrides the
+@code{maxsamples} directive (@pxref{maxsamples directive}).
@end table
@c }}}
@@ -2787,11 +2922,11 @@ required (the default is 123, the standard NTP port).
Although @code{chronyd} will trim the rate at which it samples the
server during normal operation, the user may wish to constrain the
minimum polling interval. This is always defined as a power of 2, so
-<tt/minpoll 5/ would mean that the polling interval cannot drop below 32
+@code{minpoll 5} would mean that the polling interval cannot drop below 32
seconds. The default is 6 (64 seconds).
@item maxpoll
In a similar way, the user may wish to constrain the maximum polling
-interval. Again this is specified as a power of 2, so <tt/maxpoll 9/
+interval. Again this is specified as a power of 2, @code{maxpoll 9}
indicates that the polling interval must stay at or below 512 seconds.
The default is 10 (1024 seconds).
@item maxdelay
@@ -2811,9 +2946,9 @@ some sort).
If the user knows that round trip delays above a certain level should
cause the measurement to be ignored, this level can be defined with the
-maxdelay command. For example, <tt/maxdelay 0.3/ would indicate that
+maxdelay command. For example, @code{maxdelay 0.3} would indicate that
measurements with a round-trip delay of 0.3 seconds or more should be
-ignored.
+ignored. The default value is 3 seconds.
@item maxdelayratio
This option is similar to the maxdelay option above. @code{chronyd}
@@ -2900,14 +3035,78 @@ Target number of measurements to use for the regression algorithm which
@code{minpoll} and @code{maxpoll}. A higher target makes @code{chronyd} prefer
shorter polling intervals. The default is 6 and a useful range is 6 to 60.
+@item version
+This option sets the NTP version number used in packets sent to the server.
+This can be useful when the server runs an old NTP implementation that doesn't
+respond to newer versions. The default version number is 4.
+
@item prefer
Prefer this source over sources without prefer option.
@item noselect
Never select this source. This is particularly useful for monitoring.
+@item minsamples
+Set the minimum number of samples kept for this source. This overrides the
+@code{minsamples} directive (@pxref{minsamples directive}).
+
+@item maxsamples
+Set the maximum number of samples kept for this source. This overrides the
+@code{maxsamples} directive (@pxref{maxsamples directive}).
+
@end table
@c }}}
+@c {{{ smoothtime
+@node smoothtime directive
+@subsection smoothtime
+The @code{smoothtime} directive can be used to enable smoothing of the time
+that @code{chronyd} serves to its clients to make it easier for them to track
+it and keep their clocks close together even when large offset or frequency
+corrections are applied to the server's clock, for example after being offline
+for a longer time.
+
+BE WARNED - the server is intentionally not serving its best estimate of the
+true time. If a large offset has been accumulated, it may take a very long
+time to smooth it out. This directive should be used only when the clients are
+not configured to poll also another NTP server, because they could reject this
+server as a falseticker or fail to select a source completely.
+
+The smoothing process is implemented with a quadratic spline function with two
+or three pieces. It's independent from any slewing applied to the local system
+clock, but the accumulated offset and frequency will be reset when the clock is
+corrected by stepping, e.g. by the @code{makestep} directive or command. The
+process can be reset without stepping the clock by the @code{smoothtime reset}
+command (@pxref{smoothtime command}).
+
+The first two arguments of the directive are the maximum frequency offset of
+the smoothed time to the tracked NTP time (in ppm) and the maximum rate at
+which the frequency offset is allowed to change (in ppm per second).
+@code{leaponly} is an optional third argument which enables a mode where only
+leap seconds are smoothed out and normal offset/frequency changes are ignored.
+The @code{leaponly} option is useful in a combination with the
+@code{leapsecmode slew} option (@pxref{leapsecmode directive}) to allow clients
+use multiple time smoothing servers safely.
+
+The smoothing process is activated automatically when 1/10000 of the estimated
+skew of the local clock falls below the maximum rate of frequency change. It
+can be also activated manually by the @code{smoothtime activate} command,
+which is particularly useful when the clock is synchronized only with manual
+input and the skew is always larger than the threshold. The @code{smoothing}
+command (@pxref{smoothing command}) can be used to monitor the process.
+
+An example suitable for clients using @code{ntpd} and 1024 second polling
+interval could be
+
+@example
+smoothtime 400 0.001
+@end example
+
+An example suitable for clients using @code{chronyd} on Linux could be
+
+@example
+smoothtime 50000 0.01
+@end example
+@c }}}
@c {{{ stratumweight
@node stratumweight directive
@subsection stratumweight
@@ -2922,30 +3121,31 @@ The syntax is
stratumweight <dist-in-seconds>
@end example
-By default, it is 1 second. This usually means that sources with lower stratum
-will be preferred to sources with higher stratum even when their distance is
-significantly worse. Setting @code{stratumweight} to 0 makes @code{chronyd}
-ignore stratum when selecting the source.
+By default, the weight is 0.001 seconds. This means that stratum of the
+sources in the selection process matters only when the differences between the
+distances are in milliseconds.
@c }}}
@c {{{ tempcomp
@node tempcomp directive
@subsection tempcomp
-Normally, changes in rate of drift of the system clock are caused mainly by
-changes in temperature of the crystal oscillator on the mainboard.
-
-If there are available temperature measurements from a sensor close to the
-oscillator, @code{tempcomp} directive can be used to compensate for the changes
-in rate and possibly improve clock accuracy.
-
-Whether it will really help depends on many factors, including resolution of
-the sensor, noise in measurements, time source polling interval, compensation
-update interval, how good are the temperature coefficients, and how close is
-the sensor to the oscillator. The frequency reported in tracking.log should
-be more stable and the offsets should be smaller.
-
-The directive has six parameters: path to the file which contains current
-temperature in text format, update interval (in seconds), and temperature
+Normally, changes in the rate of drift of the system clock are caused mainly by
+changes in the temperature of the crystal oscillator on the mainboard.
+
+If there are temperature measurements available from a sensor close to the
+oscillator, the @code{tempcomp} directive can be used to compensate for the
+changes in the temperature and improve the stability and accuracy of the clock.
+
+The result depends on many factors, including the resolution of the sensor,
+the amount of noise in the measurements, the polling interval of the time
+source, the compensation update interval, how well is the compensation
+specified, and how close is the sensor to the oscillator. When it's working
+well, the frequency reported in the @file{tracking.log} file is more stable and
+the maximum reached offset is smaller.
+
+There are two forms of the directive. The first one has six parameters: a
+path to the file containing the current temperature from the sensor (in
+text format), the compensation update interval (in seconds), and temperature
coefficients T0, k0, k1, k2.
The frequency compensation is calculated (in ppm) as
@@ -2953,23 +3153,48 @@ The frequency compensation is calculated (in ppm) as
@code{k0 + (T - T0) * k1 + (T - T0)^2 * k2}
The result has to be between -10 ppm and 10 ppm, otherwise the measurement is
-considered to be faulty and will be ignored. The k0 coefficient can be used to
-get the results in that range.
-
-Valid measurements and calculated corrections are logged to tempcomp.log file if
-enabled with @code{log tempcomp} directive.
+considered invalid and will be ignored. The k0 coefficient can be used to get
+the results in that range.
An example of use is
@example
-tempcomp /sys/class/hwmon/hwmon1/device/temp2_input 30 26000 0.0 0.000183 0.0
+tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 26000 0.0 0.000183 0.0
+@end example
+
+The measured temperature will be read from the file in the Linux sysfs
+filesystem every 30 seconds. When the temperature is 26000 (26 degrees
+Celsius), the frequency correction will be zero. When it is 27000 (27 degrees
+Celsius), the clock will be set to run 0.183ppm faster, etc.
+
+The second form has three parameters, the path to the sensor file, the update
+interval and a path to a file containing a list of (temperature, compensation)
+points, from which the compensation is linearly interpolated or extrapolated.
+
+An example is
+
+@example
+tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 /etc/chrony.tempcomp
@end example
-The measured temperature will be read from the file in Linux sysfs filesystem
-every 30 seconds. When the temperature is 26 degress (26000), the system clock
-frequency will not be adjusted. When it is 27 degrees (27000), the clock will
-be set to run 0.183ppm faster than it would be without the compensation, etc.
+where the @file{chrony.tempcomp} file could have
+
+@example
+20000 1.0
+21000 0.64
+22000 0.36
+23000 0.16
+24000 0.04
+25000 0.0
+26000 0.04
+27000 0.16
+28000 0.36
+29000 0.64
+30000 1.0
+@end example
+Valid measurements with corresponding compensations are logged to the
+@file{tempcomp.log} file if enabled by the @code{log tempcomp} directive.
@c }}}
@c {{{ user
@node user directive
@@ -3096,6 +3321,7 @@ password:
@item @code{password}
@item @code{quit}
@item @code{rtcdata}
+@item @code{smoothing}
@item @code{sources}
@item @code{sourcestats}
@item @code{tracking}
@@ -3137,7 +3363,7 @@ interface.
* exit command:: Exit from chronyc
* help command:: Generate help summary
* local command:: Let computer be a server when it is unsynchronised
-* makestep command:: Immediately correct the system clock instead of slewing
+* makestep command:: Correct the system clock by stepping instead of slewing
* manual command:: Enable/disable/configure options for settime
* maxdelay command:: Set max measurement delay for a source
* maxdelaydevratio command:: Set max measurement delay for a source as ratio to deviation
@@ -3156,6 +3382,8 @@ interface.
* retries command:: Set maximum number of retries
* rtcdata command:: Display RTC parameters
* settime command:: Provide a manual input of the current time
+* smoothing command:: Display current time smoothing state
+* smoothtime command:: Reset/activate server time smoothing
* sources command:: Display information about the current set of sources
* sourcestats command:: Display the rate & offset estimation performance of sources
* timeout command:: Set initial response timeout
@@ -3175,7 +3403,7 @@ Examples of use, showing a named host and a numeric IP address, are as
follows:
@example
-accheck a.b.c
+accheck foo.example.net
accheck 1.2.3.4
accheck 2001:db8::1
@end example
@@ -3216,13 +3444,16 @@ The @code{add peer} command allows a new NTP peer to be added whilst
@code{chronyd} is running.
Following the words @code{add peer}, the syntax of the following
-parameters and options is identical to that for the @code{peer}
+parameters and options is similar to that for the @code{peer}
directive in the configuration file (@pxref{peer directive}).
+The following peer options can be set in the command:
+@code{port}, @code{minpoll}, @code{maxpoll}, @code{presend},
+@code{maxdelayratio}, @code{maxdelay}, @code{key}
An example of using this command is shown below.
@example
-add peer foo.bar.com minpoll 6 maxpoll 10 authkey 25
+add peer foo.example.net minpoll 6 maxpoll 10 key 25
@end example
@c }}}
@c {{{ add server
@@ -3232,13 +3463,16 @@ The @code{add server} command allows a new NTP server to be added whilst
@code{chronyd} is running.
Following the words @code{add server}, the syntax of the following
-parameters and options is identical to that for the @code{server}
+parameters and options is similar to that for the @code{server}
directive in the configuration file (@pxref{server directive}).
+The following server options can be set in the command:
+@code{port}, @code{minpoll}, @code{maxpoll}, @code{presend},
+@code{maxdelayratio}, @code{maxdelay}, @code{key}
An example of using this command is shown below.
@example
-add server foo.bar.com minpoll 6 maxpoll 10 authkey 25
+add server foo.example.net minpoll 6 maxpoll 10 key 25
@end example
@c }}}
@c {{{ allow all
@@ -3256,7 +3490,7 @@ the configuration file (@pxref{allow directive}).
The syntax is illustrated in the following examples:
@example
-allow foo.bar.com
+allow foo.example.net
allow 1.2
allow 3.4.5
allow 6.7.8/22
@@ -3273,10 +3507,11 @@ directive in the configuration file.
@c {{{ authhash
@node authhash command
@subsubsection authhash
-This command sets the hash function used for authenticating user commands.
-For successful authentication the hash function has to be the same as the one
-set for the command key in the keys file on the server. It needs to be set
-before the @code{password} command is used. The default hash function is MD5.
+This command selects the hash function used for authenticating user commands.
+For successful authentication the hash function has to be the same as the
+function specified for the command key in the keys file on the server
+(@pxref{keyfile directive}). It needs to be selected before the
+@code{password} command is used. The default hash function is MD5.
An example is
@@ -3371,7 +3606,7 @@ whose IPv6 addresses have first 48 bits equal to @code{2001:db8:789a}.
Example of the three-argument form of the command is
@example
-burst 2/10 foo.bar.com
+burst 2/10 foo.example.net
@end example
@c }}}
@c {{{ clients
@@ -3435,7 +3670,7 @@ used to check whether command access is permitted from a named host.
Examples of use are as follows:
@example
-cmdaccheck a.b.c
+cmdaccheck foo.example.net
cmdaccheck 1.2.3.4
cmdaccheck 2001:db8::1
@end example
@@ -3493,7 +3728,7 @@ from the current set of sources.
The syntax is illustrated in the examples below.
@example
-delete foo.bar.com
+delete foo.example.net
delete 1.2.3.4
delete 2001:db8::1
@end example
@@ -3516,7 +3751,7 @@ directive in the configuration file (@pxref{deny directive}).
The syntax is illustrated in the following examples:
@example
-deny foo.bar.com
+deny foo.example.net
deny 1.2
deny 3.4.5
deny 6.7.8/22
@@ -3608,17 +3843,27 @@ offset, by slowing down or speeding up the clock as required. In
certain situations, the system clock may be so far adrift that this
slewing process would take a very long time to correct the system clock.
-The @code{makestep} command can be used in this situation. It cancels
-any remaining correction that was being slewed, and jumps the system
-clock by the equivalent amount, making it correct immediately.
+The @code{makestep} command can be used in this situation. There are two forms
+of the command. The first form has no parameters. It tells @code{chronyd} to
+cancel any remaining correction that was being slewed and jump the system clock
+by the equivalent amount, making it correct immediately.
+
+The second form configures the automatic stepping, similarly to the
+@code{makestep} directive (@pxref{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 @code{burst} command
+to quickly make a new measurement and correct the clock by stepping if needed,
+without waiting for @code{chronyd} to complete the measurement and update the
+clock.
+
+@example
+makestep 0.1 1
+burst 1/2
+@end example
BE WARNED - certain software will be seriously affected by such jumps to
the system time. (That is the reason why chronyd uses slewing
normally.)
-
-The @code{makestep} directive in the configuration file can be used
-to step the clock automatically when the adjustment is larger than a
-specified threshold, see @ref{makestep directive}.
@c }}}
@c {{{ manual
@node manual command
@@ -3695,13 +3940,13 @@ directive}).
The following examples illustrate the syntax
@example
-maxdelay foo.bar.com 0.3
+maxdelay foo.example.net 0.3
maxdelay 1.2.3.4 0.0015
maxdelay 2001:db8::1 0.0015
@end example
The first example sets the maximum network delay allowed for a
-measurement to the host @code{foo.bar.com} to 0.3 seconds. The second
+measurement to the host @code{foo.example.net} to 0.3 seconds. The second
and third examples set the maximum network delay for a measurement to
the host with IPv4 address @code{1.2.3.4} and the host with IPv6 address
@code{2001:db8::1} to 1.5 milliseconds.
@@ -3720,7 +3965,7 @@ directive}).
The following examples illustrate the syntax
@example
-maxdelaydevratio foo.bar.com 0.1
+maxdelaydevratio foo.example.net 0.1
maxdelaydevratio 1.2.3.4 1.0
maxdelaydevratio 2001:db8::1 100.0
@end example
@@ -3736,13 +3981,13 @@ directive}).
The following examples illustrate the syntax
@example
-maxdelayratio foo.bar.com 1.5
+maxdelayratio foo.example.net 1.5
maxdelayratio 1.2.3.4 2.0
maxdelayratio 2001:db8::1 2.0
@end example
The first example sets the maximum network delay for a measurement to
-the host @code{foo.bar.com} to be 1.5 times the minimum delay found
+the host @code{foo.example.net} to be 1.5 times the minimum delay found
amongst the previous measurements that have been retained. The second
and third examples set the maximum network delay for a measurement to
the host with IPv4 address @code{1.2.3.4} and the host with IPv6
@@ -3773,10 +4018,10 @@ sampling).
An example is
@example
-maxpoll foo.bar.com 10
+maxpoll foo.example.net 10
@end example
-which sets the maximum polling interval for the host @code{foo.bar.com}
+which sets the maximum polling interval for the host @code{foo.example.net}
to 1024 seconds.
Note that the new maximum polling interval only takes effect after the
@@ -3810,10 +4055,10 @@ sampling).
An example is
@example
-minpoll foo.bar.com 5
+minpoll foo.example.net 5
@end example
-which sets the minimum polling interval for the host @code{foo.bar.com}
+which sets the minimum polling interval for the host @code{foo.example.net}
to 32 seconds.
Note that the new minimum polling interval only takes effect after the
@@ -3839,10 +4084,10 @@ IP address.
An example is
@example
-minpoll foo.bar.com 5
+minpoll foo.example.net 5
@end example
-which sets the minimum stratum for the host @code{foo.bar.com}
+which sets the minimum stratum for the host @code{foo.example.net}
to 5.
Note that the new minimum stratum only takes effect after the
@@ -3908,7 +4153,7 @@ illustrated below.
offline
offline 255.255.255.0/1.2.3.0
offline 2001:db8:789a::/48
-offline foo.bar.com
+offline foo.example.net
@end example
The second form means that the @code{offline} command is to be applied
@@ -3957,14 +4202,15 @@ password
@end example
The computer will respond with a @samp{Password:} prompt, at which you
-should enter the password and press return. (Note that the no-echo mode
-is limited to 8 characters on SunOS 4.1 due to limitations in the system
-library. Other systems do not have this restriction.)
+should enter the password and press return.
The password can be encoded as a string of characters not containing a space
with optional @code{ASCII:} prefix or as a hexadecimal number with @code{HEX:}
prefix. It has to match @code{chronyd's} currently defined command key
-(@pxref{commandkey directive}).
+(@pxref{commandkey directive}). If the command key was specified with a
+different hash function than MD5, it's necessary to select the hash function
+with the @code{authhash} command (@pxref{authhash command}) before entering the
+password.
The password command is run automatically on start if @code{chronyc} was
started with the `-a' option.
@@ -3989,10 +4235,10 @@ IP address.
An example is
@example
-polltarget foo.bar.com 12
+polltarget foo.example.net 12
@end example
-which sets the poll target for the host @code{foo.bar.com}
+which sets the poll target for the host @code{foo.example.net}
to 12.
@c }}}
@c {{{ quit
@@ -4119,6 +4365,66 @@ settime Nov 21, 1997 16:30:05
For a full description of @code{getdate}, get hold of the getdate
documentation (bundled, for example, with the source for GNU tar).
@c }}}
+@c {{{ smoothing
+@node smoothing command
+@subsubsection smoothing
+The @code{smoothing} command displays the current state of the NTP server time
+smoothing. An example of the output is shown below.
+
+@example
+Active : Yes
+Offset : +1.000268817 seconds
+Frequency : -0.142859 ppm
+Wander : -0.010000 ppm per second
+Last update : 17.8 seconds ago
+Remaining time : 19988.4 seconds
+@end example
+
+The fields are explained as follows.
+
+@table @code
+@item Active
+This shows if the server time smoothing is currently active. Possible values
+are @code{Yes} and @code{No}. If the @code{leaponly} option is included in the
+@code{smoothtime} directive, @code{(leap second only)} will be shown on the
+line.
+
+@item Offset
+This is the current offset applied to the time sent to NTP clients. Positive
+value means the clients are getting time that's ahead of true time.
+
+@item Frequency
+The current frequency offset of the served time. Negative value means the time
+observed by clients is running slower than true time.
+
+@item Wander
+The current frequency wander of the served time. Negative value means the time
+observed by clients is slowing down.
+
+@item Last update
+This field shows how long ago was the time smoothing process updated, e.g.
+@code{chronyd} accumulated a new measurement.
+
+@item Remaining time
+The time it would take for the smoothing process to get to zero offset and
+frequency if there were no more updates.
+@end table
+@c }}}
+@c {{{ smoothtime
+@node smoothtime command
+@subsubsection smoothtime
+The @code{smoothtime} command can be used to reset or activate the server time
+smoothing process if it is configured with the @code{smoothtime} directive
+(@pxref{smoothtime directive}).
+
+The syntax is as follows
+
+@example
+smoothtime reset
+smoothtime activate
+@end example
+
+@c }}}
@c {{{ sources
@node sources command
@subsubsection sources
@@ -4135,8 +4441,8 @@ columns.
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#* GPS0 0 4 377 11 -479ns[ -621ns] +/- 134ns
-^? a.b.c 2 6 377 23 -923us[ -924us] +/- 43ms
-^+ d.e.f 1 6 377 21 -2629us[-2619us] +/- 86ms
+^? foo.example.net 2 6 377 23 -923us[ -924us] +/- 43ms
+^+ bar.example.net 1 6 377 21 -2629us[-2619us] +/- 86ms
@end group
@end example
@@ -4292,7 +4598,7 @@ The @code{tracking} command displays parameters about the system's clock
performance. An example of the output is shown below.
@example
-Reference ID : 1.2.3.4 (a.b.c)
+Reference ID : 1.2.3.4 (foo.example.net)
Stratum : 3
Ref time (UTC) : Fri Feb 3 15:00:29 2012
System time : 0.000001501 seconds slow of NTP time
@@ -4323,7 +4629,7 @@ in the @file{@SYSCONFDIR@/chrony.conf} file (@pxref{local directive})).
The stratum indicates how many hops away from a computer with an
attached reference clock we are. Such a computer is a stratum-1
computer, so the computer in the example is two hops away
-(i.e. @code{a.b.c} is a stratum-2 and is synchronised from a stratum-1).
+(i.e. @code{foo.example.net} is a stratum-2 and is synchronised from a stratum-1).
@item Ref time
This is the time (UTC) at which the last measurement from the reference
@@ -4343,7 +4649,7 @@ true time (which it reports to NTP clients when it is operating in
server mode). The value reported on this line is the difference due to
this effect.
-On systems such as Solaris and SunOS, @code{chronyd} has no means to
+On systems other than Linux, @code{chronyd} doesn't
adjust the fundamental rate of the system clock, so keeps the system
time correct by periodically making offsets to it as though an error had
been measured. The build up of these offsets will be observed in this
@@ -4387,11 +4693,6 @@ This is the estimated error bound on the the frequency.
This is the total of the network path delays to the stratum-1 computer
from which the computer is ultimately synchronised.
-In certain extreme situations, this value can be negative. (This can
-arise in a symmetric peer arrangement where the computers' frequencies
-are not tracking each other and the network delay is very short relative
-to the turn-around time at each computer.)
-
@item Root dispersion
This is the total dispersion accumulated through all the computers back
to the stratum-1 computer from which the computer is ultimately
@@ -4493,317 +4794,6 @@ command is issued.
@c }}}
@c }}}
@c }}}
-@c {{{ Ch:FAQ
-@node FAQ
-@chapter Frequently asked questions
-
-@c {{{ Chapter top
-@menu
-* Administrative issues::
-* Chrony compared to other programs::
-* Configuration issues::
-* Computer is not synchronising::
-* Issues with chronyc::
-* Real-time clock issues::
-* Microsoft Windows::
-* NTP-specific issues::
-* Linux-specific issues::
-* Solaris-specific issues::
-@end menu
-@c }}}
-@c {{{ S:Administrative issues
-@node Administrative issues
-@section Administrative issues
-
-@subsection Where can I get chrony source code?
-Tarballs are available via the @code{Download} link on the chrony web site.
-For the current development from the developers' version control system see the
-@code{Git} link on the web site.
-
-@subsection Are there any packaged versions of chrony?
-We are aware of packages for Arch, Debian, Fedora, Gentoo, Mandriva, Slackware,
-Ubuntu, FreeBSD and NetBSD. We are not involved with how these are built or
-distributed.
-
-@subsection Where is the home page?
-It is currently at
-@uref{http://chrony.tuxfamily.org, http://chrony.tuxfamily.org}.
-
-@subsection Is there a mailing list?
-Yes, it's currently at @email{chrony-users@@chrony.tuxfamily.org}. There is a
-low-volume list called chrony-announce which is just for announcements of new
-releases or similar matters of high importance. You can join the lists by
-sending a message with the subject subscribe to
-@email{chrony-users-request@@chrony.tuxfamily.org} or
-@email{chrony-announce-request@@chrony.tuxfamily.org} respectively.
-
-For those who want to contribute to the development of chrony, there is a
-developers' mailing list. You can subscribe by sending mail with the subject
-subscribe to @email{chrony-dev-request@@chrony.tuxfamily.org}.
-
-@subsection What licence is applied to chrony?
-Starting from version 1.15, chrony is licensed under the GNU General Public
-License, Version 2. Versions prior to 1.15 were licensed under a custom
-BSD-like license.
-@c }}}
-@c {{{ S:Chrony compared to other programs
-@node Chrony compared to other programs
-@section Chrony compared to other programs
-@subsection 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 section @code{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
-
-@itemize @bullet
-@item slew the time to correct it when going online and NTP servers become
-visible
-@item 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.
-@item 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.
-@end itemize
-
-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.
-
-@c }}}
-@c {{{ S:Configuration issues
-@node Configuration issues
-@section Configuration issues
-
-@subsection 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 @code{local} directive to the master's
-chrony.conf file. This configuration will be better because
-
-@itemize @bullet
-@item the load on the external connection is less
-@item the load on the external NTP server(s) is less
-@item if your external connection goes down, the computers on the LAN will
-maintain a common time with each other.
-@end itemize
-
-@subsection Must I specify servers by IP address if DNS is not available on chronyd start?
-No. Starting from version 1.25, @code{chronyd} will keep trying to resolve the
-hostnames specified in the @code{server} and @code{peer} directives in
-increasing intervals until it succeeds. The @code{online} command can be
-issued from @code{chronyc} to try to resolve them immediately.
-
-@subsection How can I make chronyd more secure?
-If you don't need to serve time to NTP clients, you can add @code{port 0} to
-the @file{chrony.conf} file to disable the NTP server/peer sockets and prevent
-NTP requests from reaching @code{chronyd}.
-
-If you don't need to use @code{chronyc} remotely, you can add the following
-directives to the configuration file to bind the command sockets to the
-loopback interface
-
-@example
-bindcmdaddress 127.0.0.1
-bindcmdaddress ::1
-@end example
-
-If you don't need to use @code{chronyc} at all, you can disable the command
-sockets by adding @code{cmdport 0} to the configuration file.
-
-On Linux, if @code{chronyd} is compiled with support for Linux capabilities
-(available in the libcap library), you can specify an unprivileged user with
-the `-u' option or @code{user} directive in the @file{chrony.conf} file to drop
-root privileges after start. The configure option @code{--with-user} can be
-used to drop the privileges by default.
-
-@subsection 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 @code{chronyd} can detect falsetickers and combine measurements
-from multiple sources.
-
-There are also useful options which can be set in the @code{server} directive,
-they are @code{minpoll}, @code{maxpoll}, @code{polltarget}, @code{maxdelay},
-@code{maxdelayratio} and @code{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 suitable for public NTP servers, which normally don't allow
-too frequent polling, but if you run your own NTP servers or have permission to
-poll the servers frequently, setting the options for shorter polling intervals
-may significantly improve the accuracy of the system clock.
-
-The optimal polling interval depends on many factors, this includes 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 a server located in the same LAN could be
-
-@example
-server ntp.local minpoll 2 maxpoll 4 polltarget 30
-@end example
-
-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 @code{maxdelaydevratio} option could be added to the
-previous example
-
-@example
-server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
-@end example
-
-@c }}}
-@c {{{ S:Computer is not synchronising
-@node Computer is not synchronising
-@section Computer is not synchronising
-
-This is the most common problem. There are a number of reasons, see the
-following questions.
-
-@subsection 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 @code{log measurements}
-to the @file{chrony.conf} file and look in the measurements.log file after
-chrony has been running for a short period. See if any measurements appear.
-
-@subsection Do you have a non-permanent (i.e. intermittent) Internet connection?
-Check that you're using chronyc's @code{online} and @code{offline} commands
-appropriately. Again, check in measurements.log to see if you're getting any
-data back from the server.
-
-@subsection In measurements.log, do the '7' and '8' flag columns always show zero?
-Do you have a @code{local stratum X} directive in the @file{chrony.conf} file? If X
-is lower than the stratum of the server you're trying to use, this situation
-will arise. You should always make X quite high (e.g. 10) in this directive.
-@c }}}
-@c {{{ S:Issues with chronyc
-@node Issues with chronyc
-@section Issues with chronyc
-
-@subsection I keep getting the error @code{506 Cannot talk to daemon}
-Make sure that the @file{chrony.conf} file (on the computer where
-@code{chronyd} is running) has a @code{cmdallow} entry for the computer you are
-running @code{chronyc} on. This isn't necessary for localhost.
-
-Perhaps @code{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 @code{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.
-
-@subsection Is the chronyc<->chronyd protocol documented anywhere?
-Only by the source code :-) See cmdmon.c (@code{chronyd} side) and client.c
-(@code{chronyc} side).
-@c }}}
-@c {{{ S:Real-time clock issues
-@node Real-time clock issues
-@section Real-time clock issues
-
-@subsection 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. @code{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.
-
-@subsection 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
-@code{chronyd}. At the next reboot, @code{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
-@code{chronyd} is started after it has run.
-
-@subsection 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
-@itemize @bullet
-@item a kernel that is supported (e.g. 2.2 onwards)
-@item enhanced RTC support compiled into the kernel
-@item an @code{rtcfile} directive in your chrony.conf file
-@end itemize
-@c }}}
-@c {{{ S:Microsoft Windows
-@node Microsoft Windows
-@section Microsoft Windows
-
-@subsection Does chrony support Windows?
-No. The @code{chronyc} program (the command-line client used for configuring
-@code{chronyd} while it is running) has been successfully built and run under
-Cygwin in the past. @code{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 an NT service.
-
-@subsection 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.
-@c }}}
-@c {{{ S:NTP-specific issues
-@node NTP-specific issues
-@section NTP-specific issues
-
-@subsection Can chrony be driven from broadcast NTP servers?
-No, this NTP mode is not implemented yet.
-
-@subsection 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.
-
-@subsection Can chrony keep the system clock a fixed offset away from real time?
-This is not possible as the program currently stands.
-
-@subsection What happens if the network connection is dropped without using chronyc's 'offline' command first?
-In this case @code{chronyd} will keep trying to access the server(s) that it
-thinks are online. Eventually it will decide that they are unreachable and no
-longer consider itself synchronised to them. If you have other computers on
-your LAN accessing the computer that is affected this way, they too will become
-'unsynchronised', unless you have the 'local' directive set up on the master
-computer.
-
-The 'auto_offline' option to the 'server' entry in the chrony.conf file may be
-useful to avoid this situation.
-@c }}}
-@c {{{ S:Linux-specific issues
-@node Linux-specific issues
-@section Linux-specific issues
-
-@subsection 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.
-@c }}}
-@c {{{ S:Solaris-specific issues
-@node Solaris-specific issues
-@section Solaris-specific issues
-
-@subsection On Solaris 2.8, 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.
-@c }}}
-@c }}}
@c {{{ apx:GNU General Public License
@node GPL
@appendix GNU General Public License
diff --git a/chrony.txt b/chrony.txt
index 7eb0ba6..32fc461 100644
--- a/chrony.txt
+++ b/chrony.txt
@@ -7,32 +7,31 @@ User guide for the chrony suite
1.1 Overview
============
-Chrony is a software package for maintaining the accuracy of computer
-system clocks. It consists of a pair of programs :
-
- * 'chronyd'. This is a daemon which runs in background on the
- system. It obtains measurements (e.g. via the network) of the
- system's offset relative to other systems, and adjusts the system
- time accordingly. For isolated systems, the user can periodically
- enter the correct time by hand (using 'chronyc'). In either case,
- 'chronyd' determines the rate at which the computer gains or loses
- time, and compensates for this.
-
- 'chronyd' can also act as an NTP server, and provide a time-of-day
- service to other computers. A typical set-up is to run 'chronyd'
- on a gateway computer that has a dial-up link to the Internet, and
- use it to serve time to computers on a private LAN sitting behind
- the gateway. The IP addresses that can act as clients of 'chronyd'
- can be tightly controlled. The default is no client access.
-
- * 'chronyc'. This is a command-line driven control and monitoring
- program. An administrator can use this to fine-tune various
- parameters within the daemon, add or delete servers etc whilst the
- daemon is running.
-
- The IP addresses from which 'chronyc' clients may connect can be
- tightly controlled. The default is just the computer that
- 'chronyd' itself is running on.
+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.
+
+ 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.
+
+ 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.
+
+ The IP addresses from which 'chronyc' clients may connect can be
+tightly controlled. The default is just the computer that 'chronyd'
+itself is running on.
1.2 Acknowledgements
====================
@@ -41,11 +40,9 @@ The 'chrony' suite makes use of the algorithm known as _RSA Data
Security, Inc. MD5 Message-Digest Algorithm_ for authenticating
messages between different machines on the network.
- In writing the 'chronyd' program, extensive use has been made of
-RFC1305, written by David Mills. The 'ntp' suite's source code has been
-occasionally used to check details of the protocol that the RFC did not
-make absolutely clear. The core algorithms in 'chronyd' are all
-completely distinct from 'ntp', however.
+ In writing the 'chronyd' program, extensive use has been made of RFC
+1305 and RFC 5905, written by David Mills. The source code of the NTP
+reference implementation has been used to check details of the protocol.
1.3 Availability
================
@@ -66,22 +63,11 @@ facilities for adjusting the system clock; different operating systems
may provide different function calls to achieve this, and even where the
same function is used it may have different quirks in its behaviour.
- The software is known to work in the following environments:
- * Linux 2.2 and newer
-
- * NetBSD
- * BSD/386
-
- * Solaris 2.3/2.5/2.5.1/2.6/2.7/2.8 on Sparc (Sparc 20, Ultrasparc)
- and i386
-
- * SunOS 4.1.4 on Sparc 2 and Sparc20.
-
- Closely related systems may work too, but they have not been tested.
-
- Porting the software to other system (particularly to those
-supporting an 'adjtime' system call) should not be difficult, however it
-requires access to such systems to test out the driver.
+ The software is known to work on Linux, FreeBSD, NetBSD, Mac OS X and
+Solaris. Closely related systems may work too. Porting the software to
+other systems (particularly to those supporting an 'adjtime' system
+call) should not be difficult, however it requires access to such
+systems to test out the driver.
1.4 Relationship to other software packages
===========================================
@@ -132,11 +118,10 @@ do better than 'ntpd':
Things 'ntpd' can do that 'chronyd' can't:
- * 'ntpd' fully supports NTP version 4 (RFC5905), including broadcast,
- multicast, manycast clients / servers and the orphan mode. It also
- supports extra authentication schemes based on public-key
- cryptography (RFC5906). 'chronyd' uses NTP version 3 (RFC1305),
- which is compatible with version 4.
+ * 'ntpd' supports all operating modes from RFC 5905, including
+ broadcast, multicast and manycast client / server. It supports the
+ orphan mode and it also supports authentication based on public-key
+ cryptography described in RFC 5906.
* 'ntpd' has been ported to more types of computer / operating
system.
@@ -217,9 +202,7 @@ have some expertise in these areas, you might be able to fill the gaps.
1. Porting to other Unices
This involves creating equivalents of sys_solaris.c, sys_linux.c
- etc for the new system. Note, the Linux driver has been reported
- as working on a range of different architectures (Alpha, Sparc,
- MIPS as well as x86 of course).
+ etc for the new system.
2. Porting to Windows NT
@@ -321,14 +304,14 @@ location of the file called 'dir'. This will typically be
Now that the software is successfully installed, the next step is to
set up a configuration file. The default location of the file is
-'/etc/chrony.conf'. Suppose you want to use public NTP servers from the
-pool.ntp.org project as your time reference. A minimal useful
-configuration file could be
+'/etc/chrony.conf'. Several examples of configuration with comments are
+included in the examples directory. Suppose you want to use public NTP
+servers from the pool.ntp.org project as your time reference. A minimal
+useful configuration file could be
- server 0.pool.ntp.org iburst
- server 1.pool.ntp.org iburst
- server 2.pool.ntp.org iburst
+ pool pool.ntp.org iburst
makestep 10 3
+ rtcsync
Then, 'chronyd' can be run.
@@ -432,25 +415,37 @@ suitable servers by one of the following methods:
Assuming that you have found some servers, you need to set up a
configuration file to run chrony. The (compiled-in) default location
-for this file is '/etc/chrony.conf'. Assuming that your ntp servers are
-called 'a.b.c' and 'd.e.f', your 'chrony.conf' file could contain as a
-minimum
+for this file is '/etc/chrony.conf'. Assuming that your NTP servers are
+called 'foo.example.net', 'bar.example.net' and 'baz.example.net', your
+'chrony.conf' file could contain as a minimum
- server a.b.c
- server d.e.f
- server g.h.i
+ server foo.example.net
+ server bar.example.net
+ server baz.example.net
However, you will probably want to include some of the other
-directives described later. The 'driftfile' and 'makestep' directives
-may be particularly useful. 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
+directives described later. The following directives may be
+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 foo.example.net iburst
+ server bar.example.net iburst
+ server baz.example.net iburst
+ driftfile /var/lib/chrony/drift
+ makestep 10 3
+ rtcsync
+
+ 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
+
+ pool pool.ntp.org iburst
driftfile /var/lib/chrony/drift
makestep 10 3
+ rtcsync
3.2 Infrequent connection to true NTP servers
=============================================
@@ -469,12 +464,13 @@ internet. The same remarks apply for how to find them.
saves the program from continuously trying to poll the servers when they
are inaccessible.
- Again, assuming that your ntp servers are called 'a.b.c' and 'd.e.f',
-your 'chrony.conf' file would need to contain something like
+ Again, assuming that your NTP servers are called 'foo.example.net',
+'bar.example.net' and 'baz.example.net', your 'chrony.conf' file would
+need to contain something like
- server a.b.c
- server d.e.f
- server g.h.i
+ server foo.example.net
+ server bar.example.net
+ server baz.example.net
However, your computer will keep trying to contact the servers to
obtain timestamps, even whilst offline. If you operate a dial-on-demand
@@ -484,9 +480,9 @@ keep getting established.
For this reason, it would be better to specify this part of your
configuration file in the following way:
- server a.b.c offline
- server d.e.f offline
- server g.h.i offline
+ server foo.example.net offline
+ server bar.example.net offline
+ server baz.example.net offline
The 'offline' keyword indicates that the servers start in an offline
state, and that they should not be contacted until 'chronyd' receives
@@ -501,9 +497,9 @@ automatically on the first 'chronyd' start.
The smallest useful configuration file would look something like
- server a.b.c offline
- server d.e.f offline
- server g.h.i offline
+ server foo.example.net offline
+ server bar.example.net offline
+ server baz.example.net offline
keyfile /etc/chrony.keys
generatecommandkey
driftfile /var/lib/chrony/drift
@@ -695,9 +691,9 @@ configuration files are shown in this section.
For the '/etc/chrony.conf' file, the following can be used as an
example.
- server 0.pool.ntp.org maxdelay 0.4 offline
- server 1.pool.ntp.org maxdelay 0.4 offline
- server 2.pool.ntp.org maxdelay 0.4 offline
+ server foo.example.net maxdelay 0.4 offline
+ server bar.example.net maxdelay 0.4 offline
+ server baz.example.net maxdelay 0.4 offline
logdir /var/log/chrony
log statistics measurements tracking
driftfile /var/lib/chrony/drift
@@ -801,8 +797,7 @@ the command
install a new version. However, it only makes sense on systems
where the kernel can maintain clock compensation whilst not under
'chronyd'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.
+ Linux. On other systems this option should not be used.
'-R'
When this option is used, the 'initstepslew' directive and the
'makestep' directive used with a positive limit will be ignored.
@@ -961,7 +956,7 @@ clients.
Examples of use of the command are as follows:
- allow foo.bar.com
+ allow foo.example.net
allow 1.2
allow 3.4.5
allow 6.7.8/22
@@ -1041,46 +1036,30 @@ the internet connection. You could add the line
to the configuration file.
- This directive affects NTP (UDP port 123 by default) packets. If no
-'bindcmdaddress' directive is present, the address supplied by
-'bindaddress' will be used to control binding of the command socket (UDP
-port 323 by default) as well.
-
- The 'bindaddress' directive has been found to cause problems when
-used on computers that need to pass NTP traffic over multiple network
-interfaces (e.g. firewalls). It is, therefore, not particularly
-useful. Use of the 'allow' and 'deny' directives together with a
-network firewall is more likely to be successful.
-
For each of IPv4 and IPv6 protocols, only one 'bindaddress' directive
-can be specified.
+can be specified. Therefore, it's not useful on computers which should
+serve NTP on multiple network interfaces.
4.2.6 bindcmdaddress
--------------------
-The 'bindcmdaddress' directive allows you to restrict the network
+The 'bindcmdaddress' directive allows you to specify the network
interface to which 'chronyd' will listen for command packets (issued by
'chronyc'). This provides an additional level of access restriction
above that available through 'cmddeny' mechanism.
- Suppose you want to block all access except from localhost. You
-could add the lines
+ By default, 'chronyd' binds to the loopback interface (with addresses
+'127.0.0.1' and '::1'). This blocks all access except from localhost.
+To listen for command packets on all interfaces, you can add the lines
- bindcmdaddress 127.0.0.1
- bindcmdaddress ::1
+ bindcmdaddress 0.0.0.0
+ bindcmdaddress ::
to the configuration file.
For each of IPv4 and IPv6 protocols, only one 'bindcmdaddress'
directive can be specified.
- The default values are set by the 'bindaddress' directive.
-
- The 'bindcmdaddress' directive has been found to cause problems when
-used on computers that need to pass command traffic over multiple
-network interfaces. Use of the 'cmdallow' and 'cmddeny' directives
-together with a network firewall is more likely to be successful.
-
4.2.7 broadcast
---------------
@@ -1145,6 +1124,10 @@ computer.)
the 'allow all' directive (but applying to control access in this case,
of course).
+ Note that 'chronyd' has to be configured with the 'bindcmdaddress'
+directive to not listen only on the loopback interface to actually allow
+remote access.
+
4.2.10 cmddeny
--------------
@@ -1333,26 +1316,25 @@ program exits. (See the dumpdir command above).
Fallback drifts are long-term averages of the system clock drift
calculated over exponentially increasing intervals. They are used when
-the clock is unsynchronised to avoid quickly drifting away from true
-time if there was a short-term deviation in drift before the
+the clock is no longer synchronised to avoid quickly drifting away from
+true time if there was a short-term deviation in the drift before the
synchronisation was lost.
- The directive specifies the minimum and maximum interval for how long
-the system clock has to be unsynchronised to switch between fallback
-drifts. They are defined as a power of 2 (in seconds). The syntax is
-as follows
+ The directive specifies the minimum and maximum interval since last
+clock update to switch between fallback drifts. They are defined as a
+power of 2 (in seconds). The syntax is as follows
fallbackdrift 16 19
In this example, the minimum interval is 16 (18 hours) and maximum
interval is 19 (6 days). The system clock frequency will be set to the
-first fallback 18 hours after the synchronisation was lost, to the
-second after 36 hours, etc. This might be a good setting to cover daily
-and weekly temperature fluctuations.
+first fallback 18 hours after last clock update, to the second after 36
+hours, etc. This might be a good setting to cover daily and weekly
+temperature fluctuations.
By default (or if the specified maximum or minimum is 0), no
-fallbacks will be used and the clock frequency will stay at the last
-value calculated before synchronisation was lost.
+fallbacks are used and the clock frequency changes only with new
+measurements from NTP, reference clocks or manual input.
4.2.20 generatecommandkey
-------------------------
@@ -1416,15 +1398,15 @@ is used instead. This makes it easier to restart 'chronyd' whilst the
system is in normal operation.
The 'initstepslew' directive takes a threshold and a list of NTP
-servers as arguments. A maximum of 8 will be used. Each of the servers
-is rapidly polled several times, and a majority voting mechanism used to
-find the most likely range of system clock error that is present. A
-step (or slew) is applied to the system clock to correct this error.
-'chronyd' then enters its normal operating mode.
+servers as arguments. Each of the servers is rapidly polled several
+times, and a majority voting mechanism used to find the most likely
+range of system clock error that is present. A step (or slew) is
+applied to the system clock to correct this error. 'chronyd' then
+enters its normal operating mode.
An example of use of the command is
- initstepslew 30 foo.bar.com baz.quz.com
+ initstepslew 30 foo.example.net bar.example.net
where 2 NTP servers are used to make the measurement. The '30'
indicates that if the system's error is found to be 30 seconds or less,
@@ -1491,7 +1473,87 @@ SHA1.
commandkey command (see earlier). The command key can be generated
automatically on start with the 'generatecommandkey' directive.
-4.2.25 leapsectz
+4.2.25 leapsecmode
+------------------
+
+A leap second is an adjustment that is occasionally applied to UTC to
+keep it close to the mean solar time. When a leap second is inserted,
+the last day of June or December has an extra second 23:59:60.
+
+ For computer clocks that is a problem. The Unix time is defined as
+number of seconds since 00:00:00 UTC on 1 January 1970 without leap
+seconds. The system clock cannot have time 23:59:60, every minute has
+60 seconds and every day has 86400 seconds by definition. The inserted
+leap second is skipped and the clock is suddenly ahead of UTC by one
+second. The 'leapsecmode' directive selects how that error is
+corrected. There are four options:
+
+'system'
+ When inserting a leap second, the kernel steps the system clock
+ backwards by one second when the clock gets to 00:00:00 UTC. When
+ deleting a leap second, it steps forward by one second when the
+ clock gets to 23:59:59 UTC. This is the default mode when the
+ system driver supports leap seconds (currently Linux only).
+'step'
+ This is similar to the 'system' mode, except the clock is stepped
+ by 'chronyd' instead of the kernel. It can be useful to avoid bugs
+ in the kernel code that would be executed in the 'system' mode.
+ This is the default mode when the system driver doesn't support
+ leap seconds.
+'slew'
+ The clock is corrected by slewing started at 00:00:00 UTC when a
+ leap second is inserted or 23:59:59 UTC when a leap second is
+ deleted. This may be preferred over the 'system' and 'step' modes
+ when applications running on the system are sensitive to jumps in
+ the system time and it's acceptable that the clock will be off for
+ a longer time. On Linux with the default 'maxslewrate' value
+ (*note maxslewrate directive::) the correction takes 12 seconds.
+'ignore'
+ No correction is applied to the clock for the leap second. The
+ clock will be corrected later in normal operation when new
+ measurements are made and the estimated offset includes the one
+ second error.
+
+ An example of the command is
+
+ leapsecmode slew
+
+ When serving time to NTP clients that can't be configured to correct
+their clocks for a leap second by slewing or they would correct them at
+slightly different rates when it's necessary to keep them close
+together, the 'slew' mode can be combined with the 'smoothtime'
+directive (*note smoothtime directive::) to enable a server leap smear.
+
+ When smearing a leap second, the leap status is suppressed on the
+server and the served time is corrected slowly be slewing instead of
+stepping. The clients don't need any special configuration as they
+don't know there is any leap second and they follow the server time
+which eventually brings them back to UTC. Care must be taken to ensure
+they use for synchronization only NTP servers which smear the leap
+second in exactly the same way.
+
+ This feature needs to be used carefully, because the server is
+intentionally not serving its best estimate of the true time.
+
+ A recommended configuration to enable a server leap smear is:
+
+ leapsecmode slew
+ maxslewrate 1000
+ smoothtime 400 0.001 leaponly
+
+ The first directive is necessary to disable the clock step which
+would reset the smoothing process. The second directive limits the
+slewing rate of the local clock to 1000 ppm, which improves the
+stability of the smoothing process when the local correction starts and
+ends. The third directive enables the server time smoothing process.
+It will start when the clock gets to 00:00:00 UTC and it will take 17
+hours 34 minutes to finish. The frequency offset will be changing by
+0.001 ppm per second and will reach maximum of 31.623 ppm. The
+'leaponly' option makes the duration of the leap smear constant and
+allows the clients to safely synchronise with multiple identically
+configured leap smearing servers.
+
+4.2.26 leapsectz
----------------
This directive is used to set the name of the timezone in the system tz
@@ -1513,7 +1575,7 @@ seconds and can be used with this directive
$ TZ=right/UTC date -d 'Dec 31 2008 23:59:60'
Wed Dec 31 23:59:60 UTC 2008
-4.2.26 local
+4.2.27 local
------------
The local keyword is used to allow 'chronyd' to appear synchronised to
@@ -1545,7 +1607,7 @@ like 10 for the local command prevents the machine's own time from ever
being confused with real time, were it ever to leak out to clients that
have visibility of real servers.
-4.2.27 lock_all
+4.2.28 lock_all
---------------
The 'lock_all' directive will lock chronyd into RAM so that it will
@@ -1556,7 +1618,7 @@ consistent latency. It should not have significant impact on
performance as 'chronyd's' memory usage is modest. The mlockall man
page has more details.
-4.2.28 log
+4.2.29 log
----------
The log command indicates that certain information is to be logged.
@@ -1590,19 +1652,19 @@ command.
log measurements statistics tracking
-4.2.28.1 Measurements log file format
+4.2.29.1 Measurements log file format
.....................................
An example line (which actually appears as a single line in the file)
from the measurements log file is shown below.
- 2010-12-22 05:40:50 158.152.1.76 N 8 1111 111 1111 10 10 1.0 \
+ 2014-10-13 05:40:50 158.152.1.76 N 2 111 111 1111 10 10 1.0 \
-4.966e-03 2.296e-01 1.577e-05 1.615e-01 7.446e-03
The columns are as follows (the quantities in square brackets are the
values from the example line above) :
- 1. Date [2010-12-22]
+ 1. Date [2014-10-13]
2. Hour:Minute:Second [05:40:50]. Note that the date/time pair is
expressed in UTC, not the local time zone.
3. IP address of server/peer from which measurement comes
@@ -1612,27 +1674,29 @@ values from the example line above) :
the month has 59 seconds, '?' means the remote computer is not
currently synchronised.) [N]
5. Stratum of remote computer. [2]
- 6. RFC1305 tests 1 through 4 (1=pass, 0=fail) [1111]
- 7. Tests for maximum delay, maximum delay ratio and maximum delay dev
- ratio, against defined parameters (1=pass, 0=fail) [111]
- 8. RFC1305 tests 5 through 8 (1=pass, 0=fail) [1111]
+ 6. RFC 5905 tests 1 through 3 (1=pass, 0=fail) [111]
+ 7. RFC 5905 tests 5 through 7 (1=pass, 0=fail) [111]
+ 8. Tests for maximum delay, maximum delay ratio and maximum delay dev
+ ratio, against defined parameters, and a test for synchronisation
+ loop (1=pass, 0=fail) [1111]
9. Local poll [10]
10. Remote poll [10]
11. 'Score' (an internal score within each polling level used to
decide when to increase or decrease the polling level. This is
adjusted based on number of measurements currently being used for
the regression algorithm). [1.0]
- 12. The estimated local clock error ('theta' in RFC1305). Positive
- indicates that the local clock is slow. [-4.966e-03].
- 13. The peer delay ('delta' in RFC1305). [2.296e-01]
- 14. The peer dispersion ('epsilon' in RFC1305). [1.577e-05]
- 15. The root delay ('Delta' in RFC1305). [1.615e-01]
- 16. The root dispersion ('E' in RFC1305). [7.446e-03]
+ 12. The estimated local clock error ('theta' in RFC 5905). Positive
+ indicates that the local clock is slow of the remote source.
+ [-4.966e-03].
+ 13. The peer delay ('delta' in RFC 5905). [2.296e-01]
+ 14. The peer dispersion ('epsilon' in RFC 5905). [1.577e-05]
+ 15. The root delay ('DELTA' in RFC 5905). [1.615e-01]
+ 16. The root dispersion ('EPSILON' in RFC 5905). [7.446e-03]
A banner is periodically written to the log file to indicate the
meanings of the columns.
-4.2.28.2 Statistics log file format
+4.2.29.2 Statistics log file format
...................................
An example line (which actually appears as a single line in the file)
@@ -1681,7 +1745,7 @@ values from the example line above) :
A banner is periodically written to the log file to indicate the
meanings of the columns.
-4.2.28.3 Tracking log file format
+4.2.29.3 Tracking log file format
.................................
An example line (which actually appears as a single line in the file)
@@ -1719,7 +1783,7 @@ values from the example line above) :
A banner is periodically written to the log file to indicate the
meanings of the columns.
-4.2.28.4 Real-time clock log file format
+4.2.29.4 Real-time clock log file format
........................................
An example line (which actually appears as a single line in the file)
@@ -1757,7 +1821,7 @@ values from the example line above) :
A banner is periodically written to the log file to indicate the
meanings of the columns.
-4.2.28.5 Refclocks log file format
+4.2.29.5 Refclocks log file format
..................................
An example line (which actually appears as a single line in the file)
@@ -1788,7 +1852,7 @@ values from the example line above) :
A banner is periodically written to the log file to indicate the
meanings of the columns.
-4.2.28.6 Tempcomp log file format
+4.2.29.6 Tempcomp log file format
.................................
An example line (which actually appears as a single line in the file)
@@ -1810,7 +1874,7 @@ values from the example line above) :
A banner is periodically written to the log file to indicate the
meanings of the columns.
-4.2.29 logbanner
+4.2.30 logbanner
----------------
A banner is periodically written to the log files enabled by the 'log'
@@ -1820,7 +1884,7 @@ directive to indicate the meanings of the columns.
file should be the banner written. The default is 32, and 0 can be used
to disable it entirely.
-4.2.30 logchange
+4.2.31 logchange
----------------
This directive forces 'chronyd' to send a message to syslog if it makes
@@ -1840,7 +1904,7 @@ somebody can see them. This allows that person to see if a large error
has arisen, e.g. because of a fault, or because of faulty timezone
handling, for example when summer time (daylight saving) starts or ends.
-4.2.31 logdir
+4.2.32 logdir
-------------
This directive allows the directory where log files are written to be
@@ -1850,7 +1914,7 @@ specified.
logdir /var/log/chrony
-4.2.32 mailonchange
+4.2.33 mailonchange
-------------------
This directive defines an email address to which mail should be sent if
@@ -1864,7 +1928,7 @@ system clock.
This would send a mail message to root if a change of more than 0.5
seconds were applied to the system clock.
-4.2.33 makestep
+4.2.34 makestep
---------------
Normally chronyd will cause the system to gradually correct any time
@@ -1888,7 +1952,7 @@ with NTP sources.
This would step system clock if the adjustment is larger than 1000
seconds, but only in the first ten clock updates.
-4.2.34 manual
+4.2.35 manual
-------------
The 'manual' directive enables support at run-time for the 'settime'
@@ -1902,7 +1966,7 @@ two commands is that the 'manual' command controls the manual clock
driver's behaviour, whereas the 'settime' command allows samples of
manually entered time to be provided).
-4.2.35 maxchange
+4.2.36 maxchange
----------------
This directive sets the maximum allowed offset corrected on a clock
@@ -1921,7 +1985,7 @@ message is sent to syslog.
every clock update, it will ignore two adjustments larger than 1000
seconds and exit on another one.
-4.2.36 maxclockerror
+4.2.37 maxclockerror
--------------------
The 'maxclockerror' directive sets the maximum assumed frequency error
@@ -1938,18 +2002,20 @@ absolute frequency error.
to 0.1 for a high quality clock using a temperature compensated crystal
oscillator.
-4.2.37 maxsamples
+4.2.38 maxsamples
-----------------
-The 'maxsamples' directive sets the maximum number of samples 'chronyd'
-should keep for each source. The default is 0, which disables the
-configurable limit, and the useful range is 4 to 64.
+The 'maxsamples' directive sets the default maximum number of samples
+'chronyd' should keep for each source. This setting can be overriden
+for individual sources in the 'server' and 'refclock' directives (*note
+server directive::, *note refclock directive::). The default value is
+0, which disables the configurable limit. The useful range is 4 to 64.
The syntax is
maxsamples <samples>
-4.2.38 maxslewrate
+4.2.39 maxslewrate
------------------
The 'maxslewrate' directive sets the maximum rate at which 'chronyd' is
@@ -1964,7 +2030,7 @@ Linux).
maxslewrate <rate-in-ppm>
-4.2.39 maxupdateskew
+4.2.40 maxupdateskew
--------------------
One of 'chronyd's' tasks is to work out how fast or slow the computer's
@@ -1997,32 +2063,65 @@ highly-reliable master estimate and a new estimate is generated which
has large error bounds, the existing master estimate will dominate in
the new master estimate.
-4.2.40 minsamples
+4.2.41 minsamples
-----------------
-The 'minsamples' directive sets the minimum number of samples 'chronyd'
-should try to keep for each source. The default is 0 and the useful
-range is 4 to 64.
+The 'minsamples' directive sets the default minimum number of samples
+'chronyd' should keep for each source. This setting can be overriden
+for individual sources in the 'server' and 'refclock' directives (*note
+server directive::, *note refclock directive::). The default value is
+0. The useful range is 4 to 64.
The syntax is
minsamples <samples>
-4.2.41 noclientlog
+4.2.42 minsources
+-----------------
+
+The 'minsources' directive sets the minimum number of sources that need
+to be considered as selectable in the source selection algorithm before
+the local clock is updated. The default value is 1.
+
+ Setting this option to a larger number can be used to improve the
+reliability. More sources will have to agree with each other and the
+clock will not be updated when only one source (which could be serving
+wrong time) is reachable.
+
+ The syntax is
+
+ minsources <sources>
+
+4.2.43 noclientlog
------------------
This directive, which takes no arguments, specifies that client accesses
are not to be logged. Normally they are logged, allowing statistics to
be reported using the 'clients' command in 'chronyc'.
-4.2.42 peer
+4.2.44 peer
-----------
The syntax of this directive is identical to that for the 'server'
directive (*note server directive::), except that it is used to specify
an NTP peer rather than an NTP server.
-4.2.43 pidfile
+ Please note that NTP peers that are not configured with a key to
+enable authentication are vulnerable to a denial-of-service attack. An
+attacker knowing that NTP hosts A and B are peering with each other 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.
+
+ This attack can be prevented by enabling authentication with the key
+option, or using the 'server' directive on both sides to specify the
+other host as a server instead of peer, the only drawback is that it
+will double the network traffic between the two hosts.
+
+4.2.45 pidfile
--------------
chronyd always writes its process ID (pid) to a file, and checks this
@@ -2032,14 +2131,40 @@ system. By default, the file used is '/var/run/chronyd.pid'. The
pidfile /var/tmp/chronyd.pid
-4.2.44 port
+4.2.46 pool
+-----------
+
+The syntax of this directive is similar to that for the 'server'
+directive (*note server directive::), except that it is used to specify
+a pool of NTP servers rather than a single NTP server. The pool name is
+expected to resolve to multiple addresses which may change over time.
+
+ All options valid in the 'server' directive can be used in this
+directive too. There is one option specific to '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. When a pool source is unreachable or
+marked as falseticker, 'chronyd' will try to replace the source with a
+newly resolved address of the pool.
+
+ An example of the pool directive is
+
+ pool pool.ntp.org iburst maxsources 3
+
+4.2.47 port
-----------
This option allows you to configure the port on which 'chronyd' will
-listen for NTP requests.
+listen for NTP requests. The port will be open only when an address is
+allowed by the 'allow' directive or command, an NTP peer is configured,
+or the broadcast server mode is enabled.
The compiled in default is udp/123, the standard NTP port. If set to
-0, 'chronyd' will not open the server socket and will operate strictly
+0, 'chronyd' will never open the server port and will operate strictly
in a client-only mode. The source port used in NTP client requests can
be set by the 'acquisitionport' directive.
@@ -2050,7 +2175,7 @@ be set by the 'acquisitionport' directive.
This would change the NTP port served by 'chronyd' on the computer to
udp/11123.
-4.2.45 refclock
+4.2.48 refclock
---------------
Reference clocks allows very accurate synchronisation and 'chronyd' can
@@ -2176,8 +2301,16 @@ be defined in any order):
Never select this source. This is useful for monitoring or with
sources which are not very accurate, but are locked with a PPS
refclock.
+'minsamples'
+ Set the minimum number of samples kept for this source. This
+ overrides the 'minsamples' directive (*note minsamples
+ directive::).
+'maxsamples'
+ Set the maximum number of samples kept for this source. This
+ overrides the 'maxsamples' directive (*note maxsamples
+ directive::).
-4.2.46 reselectdist
+4.2.49 reselectdist
-------------------
When 'chronyd' selects synchronisation source from available sources, it
@@ -2191,7 +2324,7 @@ default, the distance is 100 microseconds.
reselectdist <dist-in-seconds>
-4.2.47 rtcautotrim
+4.2.50 rtcautotrim
------------------
The 'rtcautotrim' directive is used to keep the real time clock (RTC)
@@ -2208,7 +2341,7 @@ than the specified threshold, 'chronyd' will trim the RTC as if the
This would set the threshold error to 30 seconds.
-4.2.48 rtcdevice
+4.2.51 rtcdevice
----------------
The 'rtcdevice' directive defines the name of the device file for
@@ -2218,7 +2351,7 @@ systems with devfs. An example of use is
rtcdevice /dev/misc/rtc
-4.2.49 rtcfile
+4.2.52 rtcfile
--------------
The 'rtcfile' directive defines the name of the file in which 'chronyd'
@@ -2248,7 +2381,7 @@ apply:
3. You don't have other applications that need to make use of
'/dev/rtc' at all.
-4.2.50 rtconutc
+4.2.53 rtconutc
---------------
'chronyd' assumes by default that the real time clock (RTC) keeps local
@@ -2271,7 +2404,7 @@ specifying the '-u' switch to the Linux '/sbin/hwclock' program.
Note that this setting is overriden when the 'hwclockfile' directive
(*note hwclockfile directive::) is used.
-4.2.51 rtcsync
+4.2.54 rtcsync
--------------
The 'rtcsync' directive will enable a kernel mode where the system time
@@ -2281,7 +2414,7 @@ is copied to the real time clock (RTC) every 11 minutes.
normal RTC tracking is enabled, i.e. when the 'rtcfile' directive is
used.
-4.2.52 sched_priority
+4.2.55 sched_priority
---------------------
The 'sched_priority' directive will select the SCHED_FIFO real-time
@@ -2299,7 +2432,7 @@ consistent latency since 'chronyd' will not need to wait for the
scheduler to get around to running it. You should not use this unless
you really need it. The sched_setscheduler man page has more details.
-4.2.53 server
+4.2.56 server
-------------
The 'server' directive allows NTP servers to be specified. The
@@ -2319,12 +2452,12 @@ number of subfields (which may be defined in any order):
Although 'chronyd' will trim the rate at which it samples the
server during normal operation, the user may wish to constrain the
minimum polling interval. This is always defined as a power of 2,
- so <tt/minpoll 5/ would mean that the polling interval cannot drop
+ so 'minpoll 5' would mean that the polling interval cannot drop
below 32 seconds. The default is 6 (64 seconds).
'maxpoll'
In a similar way, the user may wish to constrain the maximum
- polling interval. Again this is specified as a power of 2, so
- <tt/maxpoll 9/ indicates that the polling interval must stay at or
+ polling interval. Again this is specified as a power of 2,
+ 'maxpoll 9' indicates that the polling interval must stay at or
below 512 seconds. The default is 10 (1024 seconds).
'maxdelay'
'chronyd' uses the network round-trip delay to the server to
@@ -2343,9 +2476,9 @@ number of subfields (which may be defined in any order):
If the user knows that round trip delays above a certain level
should cause the measurement to be ignored, this level can be
- defined with the maxdelay command. For example, <tt/maxdelay 0.3/
+ defined with the maxdelay command. For example, 'maxdelay 0.3'
would indicate that measurements with a round-trip delay of 0.3
- seconds or more should be ignored.
+ seconds or more should be ignored. The default value is 3 seconds.
'maxdelayratio'
This option is similar to the maxdelay option above. 'chronyd'
@@ -2433,6 +2566,12 @@ number of subfields (which may be defined in any order):
prefer shorter polling intervals. The default is 6 and a useful
range is 6 to 60.
+'version'
+ This option sets the NTP version number used in packets sent to the
+ server. This can be useful when the server runs an old NTP
+ implementation that doesn't respond to newer versions. The default
+ version number is 4.
+
'prefer'
Prefer this source over sources without prefer option.
@@ -2440,7 +2579,67 @@ number of subfields (which may be defined in any order):
Never select this source. This is particularly useful for
monitoring.
-4.2.54 stratumweight
+'minsamples'
+ Set the minimum number of samples kept for this source. This
+ overrides the 'minsamples' directive (*note minsamples
+ directive::).
+
+'maxsamples'
+ Set the maximum number of samples kept for this source. This
+ overrides the 'maxsamples' directive (*note maxsamples
+ directive::).
+
+4.2.57 smoothtime
+-----------------
+
+The 'smoothtime' directive can be used to enable smoothing of the time
+that 'chronyd' serves to its clients to make it easier for them to track
+it and keep their clocks close together even when large offset or
+frequency corrections are applied to the server's clock, for example
+after being offline for a longer time.
+
+ BE WARNED - the server is intentionally not serving its best estimate
+of the true time. If a large offset has been accumulated, it may take a
+very long time to smooth it out. This directive should be used only
+when the clients are not configured to poll also another NTP server,
+because they could reject this server as a falseticker or fail to select
+a source completely.
+
+ The smoothing process is implemented with a quadratic spline function
+with two or three pieces. It's independent from any slewing applied to
+the local system clock, but the accumulated offset and frequency will be
+reset when the clock is corrected by stepping, e.g. by the 'makestep'
+directive or command. The process can be reset without stepping the
+clock by the 'smoothtime reset' command (*note smoothtime command::).
+
+ The first two arguments of the directive are the maximum frequency
+offset of the smoothed time to the tracked NTP time (in ppm) and the
+maximum rate at which the frequency offset is allowed to change (in ppm
+per second). 'leaponly' is an optional third argument which enables a
+mode where only leap seconds are smoothed out and normal
+offset/frequency changes are ignored. The 'leaponly' option is useful
+in a combination with the 'leapsecmode slew' option (*note leapsecmode
+directive::) to allow clients use multiple time smoothing servers
+safely.
+
+ The smoothing process is activated automatically when 1/10000 of the
+estimated skew of the local clock falls below the maximum rate of
+frequency change. It can be also activated manually by the 'smoothtime
+activate' command, which is particularly useful when the clock is
+synchronized only with manual input and the skew is always larger than
+the threshold. The 'smoothing' command (*note smoothing command::) can
+be used to monitor the process.
+
+ An example suitable for clients using 'ntpd' and 1024 second polling
+interval could be
+
+ smoothtime 400 0.001
+
+ An example suitable for clients using 'chronyd' on Linux could be
+
+ smoothtime 50000 0.01
+
+4.2.58 stratumweight
--------------------
The 'stratumweight' directive sets how much distance should be added per
@@ -2451,54 +2650,79 @@ synchronisation source from available sources.
stratumweight <dist-in-seconds>
- By default, it is 1 second. This usually means that sources with
-lower stratum will be preferred to sources with higher stratum even when
-their distance is significantly worse. Setting 'stratumweight' to 0
-makes 'chronyd' ignore stratum when selecting the source.
+ By default, the weight is 0.001 seconds. This means that stratum of
+the sources in the selection process matters only when the differences
+between the distances are in milliseconds.
-4.2.55 tempcomp
+4.2.59 tempcomp
---------------
-Normally, changes in rate of drift of the system clock are caused mainly
-by changes in temperature of the crystal oscillator on the mainboard.
+Normally, changes in the rate of drift of the system clock are caused
+mainly by changes in the temperature of the crystal oscillator on the
+mainboard.
- If there are available temperature measurements from a sensor close
-to the oscillator, 'tempcomp' directive can be used to compensate for
-the changes in rate and possibly improve clock accuracy.
+ If there are temperature measurements available from a sensor close
+to the oscillator, the 'tempcomp' directive can be used to compensate
+for the changes in the temperature and improve the stability and
+accuracy of the clock.
- Whether it will really help depends on many factors, including
-resolution of the sensor, noise in measurements, time source polling
-interval, compensation update interval, how good are the temperature
-coefficients, and how close is the sensor to the oscillator. The
-frequency reported in tracking.log should be more stable and the offsets
-should be smaller.
+ The result depends on many factors, including the resolution of the
+sensor, the amount of noise in the measurements, the polling interval of
+the time source, the compensation update interval, how well is the
+compensation specified, and how close is the sensor to the oscillator.
+When it's working well, the frequency reported in the 'tracking.log'
+file is more stable and the maximum reached offset is smaller.
- The directive has six parameters: path to the file which contains
-current temperature in text format, update interval (in seconds), and
-temperature coefficients T0, k0, k1, k2.
+ There are two forms of the directive. The first one has six
+parameters: a path to the file containing the current temperature from
+the sensor (in text format), the compensation update interval (in
+seconds), and temperature coefficients T0, k0, k1, k2.
The frequency compensation is calculated (in ppm) as
'k0 + (T - T0) * k1 + (T - T0)^2 * k2'
The result has to be between -10 ppm and 10 ppm, otherwise the
-measurement is considered to be faulty and will be ignored. The k0
+measurement is considered invalid and will be ignored. The k0
coefficient can be used to get the results in that range.
- Valid measurements and calculated corrections are logged to
-tempcomp.log file if enabled with 'log tempcomp' directive.
-
An example of use is
- tempcomp /sys/class/hwmon/hwmon1/device/temp2_input 30 26000 0.0 0.000183 0.0
+ tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 26000 0.0 0.000183 0.0
+
+ The measured temperature will be read from the file in the Linux
+sysfs filesystem every 30 seconds. When the temperature is 26000 (26
+degrees Celsius), the frequency correction will be zero. When it is
+27000 (27 degrees Celsius), the clock will be set to run 0.183ppm
+faster, etc.
+
+ The second form has three parameters, the path to the sensor file,
+the update interval and a path to a file containing a list of
+(temperature, compensation) points, from which the compensation is
+linearly interpolated or extrapolated.
+
+ An example is
+
+ tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 /etc/chrony.tempcomp
+
+ where the 'chrony.tempcomp' file could have
+
+ 20000 1.0
+ 21000 0.64
+ 22000 0.36
+ 23000 0.16
+ 24000 0.04
+ 25000 0.0
+ 26000 0.04
+ 27000 0.16
+ 28000 0.36
+ 29000 0.64
+ 30000 1.0
- The measured temperature will be read from the file in Linux sysfs
-filesystem every 30 seconds. When the temperature is 26 degress
-(26000), the system clock frequency will not be adjusted. When it is 27
-degrees (27000), the clock will be set to run 0.183ppm faster than it
-would be without the compensation, etc.
+ Valid measurements with corresponding compensations are logged to the
+'tempcomp.log' file if enabled by the 'log tempcomp' directive.
-4.2.56 user
+4.2.60 user
-----------
The 'user' directive sets the name of the user to which will 'chronyd'
@@ -2605,6 +2829,7 @@ password:
* 'password'
* 'quit'
* 'rtcdata'
+ * 'smoothing'
* 'sources'
* 'sourcestats'
* 'tracking'
@@ -2629,7 +2854,7 @@ from a particular host.
Examples of use, showing a named host and a numeric IP address, are
as follows:
- accheck a.b.c
+ accheck foo.example.net
accheck 1.2.3.4
accheck 2001:db8::1
@@ -2669,12 +2894,14 @@ The 'add peer' command allows a new NTP peer to be added whilst
'chronyd' is running.
Following the words 'add peer', the syntax of the following
-parameters and options is identical to that for the 'peer' directive in
-the configuration file (*note peer directive::).
+parameters and options is similar to that for the 'peer' directive in
+the configuration file (*note peer directive::). The following peer
+options can be set in the command: 'port', 'minpoll', 'maxpoll',
+'presend', 'maxdelayratio', 'maxdelay', 'key'
An example of using this command is shown below.
- add peer foo.bar.com minpoll 6 maxpoll 10 authkey 25
+ add peer foo.example.net minpoll 6 maxpoll 10 key 25
4.3.4.4 add server
..................
@@ -2683,12 +2910,14 @@ The 'add server' command allows a new NTP server to be added whilst
'chronyd' is running.
Following the words 'add server', the syntax of the following
-parameters and options is identical to that for the 'server' directive
-in the configuration file (*note server directive::).
+parameters and options is similar to that for the 'server' directive in
+the configuration file (*note server directive::). The following server
+options can be set in the command: 'port', 'minpoll', 'maxpoll',
+'presend', 'maxdelayratio', 'maxdelay', 'key'
An example of using this command is shown below.
- add server foo.bar.com minpoll 6 maxpoll 10 authkey 25
+ add server foo.example.net minpoll 6 maxpoll 10 key 25
4.3.4.5 allow all
.................
@@ -2704,7 +2933,7 @@ the configuration file (*note allow directive::).
The syntax is illustrated in the following examples:
- allow foo.bar.com
+ allow foo.example.net
allow 1.2
allow 3.4.5
allow 6.7.8/22
@@ -2720,11 +2949,11 @@ the configuration file (*note allow directive::).
4.3.4.7 authhash
................
-This command sets the hash function used for authenticating user
+This command selects the hash function used for authenticating user
commands. For successful authentication the hash function has to be the
-same as the one set for the command key in the keys file on the server.
-It needs to be set before the 'password' command is used. The default
-hash function is MD5.
+same as the function specified for the command key in the keys file on
+the server (*note keyfile directive::). It needs to be selected before
+the 'password' command is used. The default hash function is MD5.
An example is
@@ -2810,7 +3039,7 @@ sources whose IPv6 addresses have first 48 bits equal to
Example of the three-argument form of the command is
- burst 2/10 foo.bar.com
+ burst 2/10 foo.example.net
4.3.4.9 clients
...............
@@ -2859,7 +3088,7 @@ to check whether command access is permitted from a named host.
Examples of use are as follows:
- cmdaccheck a.b.c
+ cmdaccheck foo.example.net
cmdaccheck 1.2.3.4
cmdaccheck 2001:db8::1
@@ -2913,7 +3142,7 @@ current set of sources.
The syntax is illustrated in the examples below.
- delete foo.bar.com
+ delete foo.example.net
delete 1.2.3.4
delete 2001:db8::1
@@ -2934,7 +3163,7 @@ the configuration file (*note deny directive::).
The syntax is illustrated in the following examples:
- deny foo.bar.com
+ deny foo.example.net
deny 1.2
deny 3.4.5
deny 6.7.8/22
@@ -3022,18 +3251,27 @@ offset, by slowing down or speeding up the clock as required. In
certain situations, the system clock may be so far adrift that this
slewing process would take a very long time to correct the system clock.
- The 'makestep' command can be used in this situation. It cancels any
-remaining correction that was being slewed, and jumps the system clock
-by the equivalent amount, making it correct immediately.
+ The 'makestep' command can be used in this situation. There are two
+forms of the command. The first form has no parameters. It tells
+'chronyd' to cancel any remaining correction that was being slewed and
+jump the system clock by the equivalent amount, making it correct
+immediately.
+
+ The second form configures the automatic stepping, similarly to the
+'makestep' directive (*note 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.
+
+ makestep 0.1 1
+ burst 1/2
BE WARNED - certain software will be seriously affected by such jumps
to the system time. (That is the reason why chronyd uses slewing
normally.)
- The 'makestep' directive in the configuration file can be used to
-step the clock automatically when the adjustment is larger than a
-specified threshold, see *note makestep directive::.
-
4.3.4.25 manual
...............
@@ -3094,14 +3332,14 @@ directive in the configuration file (*note server directive::).
The following examples illustrate the syntax
- maxdelay foo.bar.com 0.3
+ maxdelay foo.example.net 0.3
maxdelay 1.2.3.4 0.0015
maxdelay 2001:db8::1 0.0015
The first example sets the maximum network delay allowed for a
-measurement to the host 'foo.bar.com' to 0.3 seconds. The second and
-third examples set the maximum network delay for a measurement to the
-host with IPv4 address '1.2.3.4' and the host with IPv6 address
+measurement to the host 'foo.example.net' to 0.3 seconds. The second
+and third examples set the maximum network delay for a measurement to
+the host with IPv4 address '1.2.3.4' and the host with IPv6 address
'2001:db8::1' to 1.5 milliseconds.
(Any measurement whose network delay exceeds the specified value is
@@ -3117,7 +3355,7 @@ directive::).
The following examples illustrate the syntax
- maxdelaydevratio foo.bar.com 0.1
+ maxdelaydevratio foo.example.net 0.1
maxdelaydevratio 1.2.3.4 1.0
maxdelaydevratio 2001:db8::1 100.0
@@ -3131,16 +3369,16 @@ directive::).
The following examples illustrate the syntax
- maxdelayratio foo.bar.com 1.5
+ maxdelayratio foo.example.net 1.5
maxdelayratio 1.2.3.4 2.0
maxdelayratio 2001:db8::1 2.0
The first example sets the maximum network delay for a measurement to
-the host 'foo.bar.com' to be 1.5 times the minimum delay found amongst
-the previous measurements that have been retained. The second and third
-examples set the maximum network delay for a measurement to the host
-with IPv4 address '1.2.3.4' and the host with IPv6 address '2001:db8::1'
-to be double the retained minimum.
+the host 'foo.example.net' to be 1.5 times the minimum delay found
+amongst the previous measurements that have been retained. The second
+and third examples set the maximum network delay for a measurement to
+the host with IPv4 address '1.2.3.4' and the host with IPv6 address
+'2001:db8::1' to be double the retained minimum.
As for 'maxdelay', any measurement whose network delay is too large
will be discarded.
@@ -3164,10 +3402,10 @@ sampling).
An example is
- maxpoll foo.bar.com 10
+ maxpoll foo.example.net 10
- which sets the maximum polling interval for the host 'foo.bar.com' to
-1024 seconds.
+ which sets the maximum polling interval for the host
+'foo.example.net' to 1024 seconds.
Note that the new maximum polling interval only takes effect after
the next measurement has been made.
@@ -3197,10 +3435,10 @@ sampling).
An example is
- minpoll foo.bar.com 5
+ minpoll foo.example.net 5
- which sets the minimum polling interval for the host 'foo.bar.com' to
-32 seconds.
+ which sets the minimum polling interval for the host
+'foo.example.net' to 32 seconds.
Note that the new minimum polling interval only takes effect after
the next measurement has been made.
@@ -3222,9 +3460,9 @@ address.
An example is
- minpoll foo.bar.com 5
+ minpoll foo.example.net 5
- which sets the minimum stratum for the host 'foo.bar.com' to 5.
+ which sets the minimum stratum for the host 'foo.example.net' to 5.
Note that the new minimum stratum only takes effect after the next
measurement has been made.
@@ -3282,7 +3520,7 @@ forms are illustrated below.
offline
offline 255.255.255.0/1.2.3.0
offline 2001:db8:789a::/48
- offline foo.bar.com
+ offline foo.example.net
The second form means that the 'offline' command is to be applied to
any source whose IPv4 address is in the '1.2.3' subnet. (The host's
@@ -3324,14 +3562,15 @@ entering the password on the command line is as follows
password
The computer will respond with a 'Password:' prompt, at which you
-should enter the password and press return. (Note that the no-echo mode
-is limited to 8 characters on SunOS 4.1 due to limitations in the system
-library. Other systems do not have this restriction.)
+should enter the password and press return.
The password can be encoded as a string of characters not containing
a space with optional 'ASCII:' prefix or as a hexadecimal number with
'HEX:' prefix. It has to match 'chronyd's' currently defined command
-key (*note commandkey directive::).
+key (*note commandkey directive::). If the command key was specified
+with a different hash function than MD5, it's necessary to select the
+hash function with the 'authhash' command (*note authhash command::)
+before entering the password.
The password command is run automatically on start if 'chronyc' was
started with the '-a' option.
@@ -3353,9 +3592,9 @@ address.
An example is
- polltarget foo.bar.com 12
+ polltarget foo.example.net 12
- which sets the poll target for the host 'foo.bar.com' to 12.
+ which sets the poll target for the host 'foo.example.net' to 12.
4.3.4.37 quit
.............
@@ -3478,7 +3717,62 @@ Consequently, you can only specify time to the nearest second.
For a full description of 'getdate', get hold of the getdate
documentation (bundled, for example, with the source for GNU tar).
-4.3.4.43 sources
+4.3.4.43 smoothing
+..................
+
+The 'smoothing' command displays the current state of the NTP server
+time smoothing. An example of the output is shown below.
+
+ Active : Yes
+ Offset : +1.000268817 seconds
+ Frequency : -0.142859 ppm
+ Wander : -0.010000 ppm per second
+ Last update : 17.8 seconds ago
+ Remaining time : 19988.4 seconds
+
+ The fields are explained as follows.
+
+'Active'
+ This shows if the server time smoothing is currently active.
+ Possible values are 'Yes' and 'No'. If the 'leaponly' option is
+ included in the 'smoothtime' directive, '(leap second only)' will
+ be shown on the line.
+
+'Offset'
+ This is the current offset applied to the time sent to NTP clients.
+ Positive value means the clients are getting time that's ahead of
+ true time.
+
+'Frequency'
+ The current frequency offset of the served time. Negative value
+ means the time observed by clients is running slower than true
+ time.
+
+'Wander'
+ The current frequency wander of the served time. Negative value
+ means the time observed by clients is slowing down.
+
+'Last update'
+ This field shows how long ago was the time smoothing process
+ updated, e.g. 'chronyd' accumulated a new measurement.
+
+'Remaining time'
+ The time it would take for the smoothing process to get to zero
+ offset and frequency if there were no more updates.
+
+4.3.4.44 smoothtime
+...................
+
+The 'smoothtime' command can be used to reset or activate the server
+time smoothing process if it is configured with the 'smoothtime'
+directive (*note smoothtime directive::).
+
+ The syntax is as follows
+
+ smoothtime reset
+ smoothtime activate
+
+4.3.4.45 sources
................
This command displays information about the current time sources that
@@ -3492,8 +3786,8 @@ of the columns.
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#* GPS0 0 4 377 11 -479ns[ -621ns] +/- 134ns
- ^? a.b.c 2 6 377 23 -923us[ -924us] +/- 43ms
- ^+ d.e.f 1 6 377 21 -2629us[-2619us] +/- 86ms
+ ^? foo.example.net 2 6 377 23 -923us[ -924us] +/- 43ms
+ ^+ bar.example.net 1 6 377 21 -2629us[-2619us] +/- 86ms
The columns are as follows:
@@ -3560,7 +3854,7 @@ of the columns.
Positive offsets indicate that the local clock is fast of the
source.
-4.3.4.44 sourcestats
+4.3.4.46 sourcestats
....................
The 'sourcestats' command displays information about the drift rate and
@@ -3617,7 +3911,7 @@ of the columns.
'Std Dev'
This is the estimated sample standard deviation.
-4.3.4.45 timeout
+4.3.4.47 timeout
................
The 'timeout' command sets the initial timeout for 'chronyc' requests in
@@ -3629,13 +3923,13 @@ configured with the 'retries' command (*note retries command::).
'chronyc' is contacting localhost (i.e. the '-h' option wasn't
specified) and 'chronyd' was compiled with asynchronous name resolving.
-4.3.4.46 tracking
+4.3.4.48 tracking
.................
The 'tracking' command displays parameters about the system's clock
performance. An example of the output is shown below.
- Reference ID : 1.2.3.4 (a.b.c)
+ Reference ID : 1.2.3.4 (foo.example.net)
Stratum : 3
Ref time (UTC) : Fri Feb 3 15:00:29 2012
System time : 0.000001501 seconds slow of NTP time
@@ -3665,7 +3959,8 @@ performance. An example of the output is shown below.
The stratum indicates how many hops away from a computer with an
attached reference clock we are. Such a computer is a stratum-1
computer, so the computer in the example is two hops away (i.e.
- 'a.b.c' is a stratum-2 and is synchronised from a stratum-1).
+ 'foo.example.net' is a stratum-2 and is synchronised from a
+ stratum-1).
'Ref time'
This is the time (UTC) at which the last measurement from the
@@ -3685,11 +3980,11 @@ performance. An example of the output is shown below.
is operating in server mode). The value reported on this line is
the difference due to this effect.
- On systems such as Solaris and SunOS, 'chronyd' has no means to
- adjust the fundamental rate of the system clock, so keeps the
- system time correct by periodically making offsets to it as though
- an error had been measured. The build up of these offsets will be
- observed in this report.
+ On systems other than Linux, 'chronyd' doesn't adjust the
+ fundamental rate of the system clock, so keeps the system time
+ correct by periodically making offsets to it as though an error had
+ been measured. The build up of these offsets will be observed in
+ this report.
'Last offset'
This is the estimated local offset on the last clock update.
@@ -3730,11 +4025,6 @@ performance. An example of the output is shown below.
This is the total of the network path delays to the stratum-1
computer from which the computer is ultimately synchronised.
- In certain extreme situations, this value can be negative. (This
- can arise in a symmetric peer arrangement where the computers'
- frequencies are not tracking each other and the network delay is
- very short relative to the turn-around time at each computer.)
-
'Root dispersion'
This is the total dispersion accumulated through all the computers
back to the stratum-1 computer from which the computer is
@@ -3753,7 +4043,7 @@ performance. An example of the output is shown below.
This is the leap status, which can be 'Normal', 'Insert second',
'Delete second' or 'Not synchronised'.
-4.3.4.47 trimrtc
+4.3.4.49 trimrtc
................
The 'trimrtc' command is used to correct the system's real time clock
@@ -3789,7 +4079,7 @@ machine reboots.
The 'trimrtc' command can be executed automatically by 'chronyd' with
the 'rtcautotrim' directive (*note rtcautotrim directive::).
-4.3.4.48 waitsync
+4.3.4.50 waitsync
.................
The 'waitsync' command waits for 'chronyd' to synchronise.
@@ -3813,7 +4103,7 @@ will not be checked.
to a source and the remaining correction to be less than 10
milliseconds.
-4.3.4.49 writertc
+4.3.4.51 writertc
.................
The 'writertc' command writes the currently estimated error and
@@ -3822,341 +4112,6 @@ the 'rtcfile' directive (*note rtcfile directive::)). This information
is also written automatically when 'chronyd' is killed (with SIGHUP,
SIGINT, SIGQUIT or SIGTERM) or when the 'trimrtc' command is issued.
-5 Frequently asked questions
-****************************
-
-5.1 Administrative issues
-=========================
-
-5.1.1 Where can I get chrony source code?
------------------------------------------
-
-Tarballs are available via the 'Download' link on the chrony web site.
-For the current development from the developers' version control system
-see the 'Git' link on the web site.
-
-5.1.2 Are there any packaged versions of chrony?
-------------------------------------------------
-
-We are aware of packages for Arch, Debian, Fedora, Gentoo, Mandriva,
-Slackware, Ubuntu, FreeBSD and NetBSD. We are not involved with how
-these are built or distributed.
-
-5.1.3 Where is the home page?
------------------------------
-
-It is currently at http://chrony.tuxfamily.org
-(http://chrony.tuxfamily.org).
-
-5.1.4 Is there a mailing list?
-------------------------------
-
-Yes, it's currently at <chrony-users@chrony.tuxfamily.org>. There is a
-low-volume list called chrony-announce which is just for announcements
-of new releases or similar matters of high importance. You can join the
-lists by sending a message with the subject subscribe to
-<chrony-users-request@chrony.tuxfamily.org> or
-<chrony-announce-request@chrony.tuxfamily.org> respectively.
-
- For those who want to contribute to the development of chrony, there
-is a developers' mailing list. You can subscribe by sending mail with
-the subject subscribe to <chrony-dev-request@chrony.tuxfamily.org>.
-
-5.1.5 What licence is applied to chrony?
-----------------------------------------
-
-Starting from version 1.15, chrony is licensed under the GNU General
-Public License, Version 2. Versions prior to 1.15 were licensed under a
-custom BSD-like license.
-
-5.2 Chrony compared to other programs
-=====================================
-
-5.2.1 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 section '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.
-
-5.3 Configuration issues
-========================
-
-5.3.1 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.
-
-5.3.2 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.
-
-5.3.3 How can I make chronyd more secure?
------------------------------------------
-
-If you don't need to serve time to NTP clients, you can add 'port 0' to
-the 'chrony.conf' file to disable the NTP server/peer sockets and
-prevent NTP requests from reaching 'chronyd'.
-
- 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
-
- 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.
-
-5.3.4 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 suitable for public NTP
-servers, which normally don't allow too frequent polling, but if you run
-your own NTP servers or have permission to poll the servers frequently,
-setting the options for shorter polling intervals may significantly
-improve the accuracy of the system clock.
-
- The optimal polling interval depends on many factors, this includes
-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 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 previous example
-
- server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
-
-5.4 Computer is not synchronising
-=================================
-
-This is the most common problem. There are a number of reasons, see the
-following questions.
-
-5.4.1 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.
-
-5.4.2 Do you have a non-permanent (i.e. intermittent) Internet connection?
---------------------------------------------------------------------------
-
-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.
-
-5.4.3 In measurements.log, do the '7' and '8' flag columns always show zero?
-----------------------------------------------------------------------------
-
-Do you have a 'local stratum X' directive in the 'chrony.conf' file? If
-X is lower than the stratum of the server you're trying to use, this
-situation will arise. You should always make X quite high (e.g. 10) in
-this directive.
-
-5.5 Issues with chronyc
-=======================
-
-5.5.1 I keep getting the error '506 Cannot talk to daemon'
-----------------------------------------------------------
-
-Make sure that the 'chrony.conf' file (on the computer where 'chronyd'
-is running) has a 'cmdallow' entry for the computer you are running
-'chronyc' on. This 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.
-
-5.5.2 Is the chronyc<->chronyd protocol documented anywhere?
-------------------------------------------------------------
-
-Only by the source code :-) See cmdmon.c ('chronyd' side) and client.c
-('chronyc' side).
-
-5.6 Real-time clock issues
-==========================
-
-5.6.1 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.
-
-5.6.2 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.
-
-5.6.3 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
-
-5.7 Microsoft Windows
-=====================
-
-5.7.1 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 an
-NT service.
-
-5.7.2 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.
-
-5.8 NTP-specific issues
-=======================
-
-5.8.1 Can chrony be driven from broadcast NTP servers?
-------------------------------------------------------
-
-No, this NTP mode is not implemented yet.
-
-5.8.2 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.
-
-5.8.3 Can chrony keep the system clock a fixed offset away from real time?
---------------------------------------------------------------------------
-
-This is not possible as the program currently stands.
-
-5.8.4 What happens if the network connection is dropped without using chronyc's 'offline' command first?
---------------------------------------------------------------------------------------------------------
-
-In this case 'chronyd' will keep trying to access the server(s) that it
-thinks are online. Eventually it will decide that they are unreachable
-and no longer consider itself synchronised to them. If you have other
-computers on your LAN accessing the computer that is affected this way,
-they too will become 'unsynchronised', unless you have the 'local'
-directive set up on the master computer.
-
- The 'auto_offline' option to the 'server' entry in the chrony.conf
-file may be useful to avoid this situation.
-
-5.9 Linux-specific issues
-=========================
-
-5.9.1 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.
-
-5.10 Solaris-specific issues
-============================
-
-5.10.1 On Solaris 2.8, 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.
-
Appendix A GNU General Public License
*************************************
@@ -4552,44 +4507,48 @@ GNU Lesser General Public License instead of this License.
4.2.22 include
4.2.23 initstepslew
4.2.24 keyfile
- 4.2.25 leapsectz
- 4.2.26 local
- 4.2.27 lock_all
- 4.2.28 log
- 4.2.28.1 Measurements log file format
- 4.2.28.2 Statistics log file format
- 4.2.28.3 Tracking log file format
- 4.2.28.4 Real-time clock log file format
- 4.2.28.5 Refclocks log file format
- 4.2.28.6 Tempcomp log file format
- 4.2.29 logbanner
- 4.2.30 logchange
- 4.2.31 logdir
- 4.2.32 mailonchange
- 4.2.33 makestep
- 4.2.34 manual
- 4.2.35 maxchange
- 4.2.36 maxclockerror
- 4.2.37 maxsamples
- 4.2.38 maxslewrate
- 4.2.39 maxupdateskew
- 4.2.40 minsamples
- 4.2.41 noclientlog
- 4.2.42 peer
- 4.2.43 pidfile
- 4.2.44 port
- 4.2.45 refclock
- 4.2.46 reselectdist
- 4.2.47 rtcautotrim
- 4.2.48 rtcdevice
- 4.2.49 rtcfile
- 4.2.50 rtconutc
- 4.2.51 rtcsync
- 4.2.52 sched_priority
- 4.2.53 server
- 4.2.54 stratumweight
- 4.2.55 tempcomp
- 4.2.56 user
+ 4.2.25 leapsecmode
+ 4.2.26 leapsectz
+ 4.2.27 local
+ 4.2.28 lock_all
+ 4.2.29 log
+ 4.2.29.1 Measurements log file format
+ 4.2.29.2 Statistics log file format
+ 4.2.29.3 Tracking log file format
+ 4.2.29.4 Real-time clock log file format
+ 4.2.29.5 Refclocks log file format
+ 4.2.29.6 Tempcomp log file format
+ 4.2.30 logbanner
+ 4.2.31 logchange
+ 4.2.32 logdir
+ 4.2.33 mailonchange
+ 4.2.34 makestep
+ 4.2.35 manual
+ 4.2.36 maxchange
+ 4.2.37 maxclockerror
+ 4.2.38 maxsamples
+ 4.2.39 maxslewrate
+ 4.2.40 maxupdateskew
+ 4.2.41 minsamples
+ 4.2.42 minsources
+ 4.2.43 noclientlog
+ 4.2.44 peer
+ 4.2.45 pidfile
+ 4.2.46 pool
+ 4.2.47 port
+ 4.2.48 refclock
+ 4.2.49 reselectdist
+ 4.2.50 rtcautotrim
+ 4.2.51 rtcdevice
+ 4.2.52 rtcfile
+ 4.2.53 rtconutc
+ 4.2.54 rtcsync
+ 4.2.55 sched_priority
+ 4.2.56 server
+ 4.2.57 smoothtime
+ 4.2.58 stratumweight
+ 4.2.59 tempcomp
+ 4.2.60 user
4.3 Running chronyc
4.3.1 Basic use
4.3.2 Command line options
@@ -4637,48 +4596,13 @@ GNU Lesser General Public License instead of this License.
4.3.4.40 retries
4.3.4.41 rtcdata
4.3.4.42 settime
- 4.3.4.43 sources
- 4.3.4.44 sourcestats
- 4.3.4.45 timeout
- 4.3.4.46 tracking
- 4.3.4.47 trimrtc
- 4.3.4.48 waitsync
- 4.3.4.49 writertc
-5 Frequently asked questions
- 5.1 Administrative issues
- 5.1.1 Where can I get chrony source code?
- 5.1.2 Are there any packaged versions of chrony?
- 5.1.3 Where is the home page?
- 5.1.4 Is there a mailing list?
- 5.1.5 What licence is applied to chrony?
- 5.2 Chrony compared to other programs
- 5.2.1 How does chrony compare to ntpd?
- 5.3 Configuration issues
- 5.3.1 I have several computers on a LAN. Should be all clients of an external server?
- 5.3.2 Must I specify servers by IP address if DNS is not available on chronyd start?
- 5.3.3 How can I make chronyd more secure?
- 5.3.4 How can I improve the accuracy of the system clock with NTP sources?
- 5.4 Computer is not synchronising
- 5.4.1 Behind a firewall?
- 5.4.2 Do you have a non-permanent (i.e. intermittent) Internet connection?
- 5.4.3 In measurements.log, do the '7' and '8' flag columns always show zero?
- 5.5 Issues with chronyc
- 5.5.1 I keep getting the error '506 Cannot talk to daemon'
- 5.5.2 Is the chronyc<->chronyd protocol documented anywhere?
- 5.6 Real-time clock issues
- 5.6.1 What is the real-time clock (RTC)?
- 5.6.2 I want to use chronyd's real-time clock support. Must I disable hwclock?
- 5.6.3 I just keep getting the '513 RTC driver not running' message
- 5.7 Microsoft Windows
- 5.7.1 Does chrony support Windows?
- 5.7.2 Are there any plans to support Windows?
- 5.8 NTP-specific issues
- 5.8.1 Can chrony be driven from broadcast NTP servers?
- 5.8.2 Can chronyd transmit broadcast NTP packets (e.g. to synchronise other computers on a private LAN)?
- 5.8.3 Can chrony keep the system clock a fixed offset away from real time?
- 5.8.4 What happens if the network connection is dropped without using chronyc's 'offline' command first?
- 5.9 Linux-specific issues
- 5.9.1 I get "Could not open /dev/rtc, Device or resource busy" in my syslog file
- 5.10 Solaris-specific issues
- 5.10.1 On Solaris 2.8, I get an error message about not being able to open kvm to change dosynctodr
+ 4.3.4.43 smoothing
+ 4.3.4.44 smoothtime
+ 4.3.4.45 sources
+ 4.3.4.46 sourcestats
+ 4.3.4.47 timeout
+ 4.3.4.48 tracking
+ 4.3.4.49 trimrtc
+ 4.3.4.50 waitsync
+ 4.3.4.51 writertc
Appendix A GNU General Public License
diff --git a/chrony_timex.h b/chrony_timex.h
deleted file mode 100644
index e262ff6..0000000
--- a/chrony_timex.h
+++ /dev/null
@@ -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 */
diff --git a/chronyc.1.in b/chronyc.1.in
index 96104d1..f738b28 100644
--- a/chronyc.1.in
+++ b/chronyc.1.in
@@ -1,4 +1,4 @@
-.TH CHRONYC 1 "April 2015" "chrony 1.31.1" "User's Manual"
+.TH CHRONYC 1 "June 2015" "chrony 2.1.1" "User's Manual"
.SH NAME
chronyc \- command-line interface for chronyd
@@ -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/
diff --git a/chronyd.8.in b/chronyd.8.in
index 39bcfdc..bafe85e 100644
--- a/chronyd.8.in
+++ b/chronyd.8.in
@@ -1,4 +1,4 @@
-.TH CHRONYD 8 "April 2015" "chrony 1.31.1" "System Administration"
+.TH CHRONYD 8 "June 2015" "chrony 2.1.1" "System Administration"
.SH NAME
chronyd \- chrony background daemon
@@ -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),
diff --git a/client.c b/client.c
index ca55b78..abe01aa 100644
--- a/client.c
+++ b/client.c
@@ -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;
@@ -69,30 +68,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");
@@ -2014,6 +1967,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)
{
CMD_Request request;
@@ -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 */
}
diff --git a/clientlog.c b/clientlog.c
index 84900b4..df38b38 100644
--- a/clientlog.c
+++ b/clientlog.c
@@ -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
@@ -387,95 +367,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)
{
diff --git a/clientlog.h b/clientlog.h
index 18fa499..a1913b5 100644
--- a/clientlog.h
+++ b/clientlog.h
@@ -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 */
diff --git a/cmdmon.c b/cmdmon.c
index 343baf4..5d5c559 100644
--- a/cmdmon.c
+++ b/cmdmon.c
@@ -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)
@@ -688,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);
@@ -706,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();
}
/* ================================================== */
@@ -741,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);
- }
}
/* ================================================== */
@@ -758,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);
- }
}
/* ================================================== */
@@ -775,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);
- }
}
/* ================================================== */
@@ -795,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);
- }
}
/* ================================================== */
@@ -813,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);
- }
}
/* ================================================== */
@@ -831,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);
- }
}
/* ================================================== */
@@ -848,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);
- }
}
/* ================================================== */
@@ -865,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);
- }
}
/* ================================================== */
@@ -882,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);
- }
}
/* ================================================== */
@@ -900,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);
- }
}
/* ================================================== */
@@ -919,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));
}
/* ================================================== */
@@ -931,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);
}
}
@@ -955,7 +906,6 @@ handle_local(CMD_Request *rx_message, CMD_Reply *tx_message)
} else {
REF_DisableLocal();
}
- tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -975,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);
}
/* ================================================== */
@@ -986,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);
}
@@ -1000,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:
@@ -1011,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);
@@ -1056,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);
@@ -1074,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)
-{
- 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 {
- tx_message->status = htons(STT_BADSUBNET);
- }
-}
-
-/* ================================================== */
-
-static void
-handle_allowall(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, 1, 1)) {
- tx_message->status = htons(STT_SUCCESS);
- } else {
- 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)
+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, 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 {
+ if (!NCR_AddAccessRestriction(&ip, subnet_bits, allow, all))
tx_message->status = htons(STT_BADSUBNET);
- }
}
/* ================================================== */
static void
-handle_cmdallowall(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 (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 {
+ if (!CAM_AddAccessRestriction(&ip, subnet_bits, allow, all))
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);
- }
}
/* ================================================== */
@@ -1261,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);
@@ -1296,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);
@@ -1316,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);
@@ -1336,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);
}
/* ================================================== */
@@ -1351,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);
}
/* ================================================== */
@@ -1362,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);
@@ -1383,18 +1230,71 @@ 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)
{
int status;
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);
@@ -1420,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);
@@ -1438,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);
- }
}
/* ================================================== */
@@ -1453,8 +1347,6 @@ static void
handle_cyclelogs(CMD_Request *rx_message, CMD_Reply *tx_message)
{
LOG_CycleLogFiles();
-
- tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1464,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) {
@@ -1507,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);
}
@@ -1521,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);
@@ -1540,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);
- }
}
/* ================================================== */
@@ -1557,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);
}
/* ================================================== */
@@ -1573,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);
}
@@ -1585,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);
}
/* ================================================== */
@@ -1594,7 +1476,6 @@ static void
handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
{
SRC_ReselectSource();
- tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1650,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:
@@ -1713,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;
@@ -1913,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:
@@ -1936,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;
@@ -1957,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) {
@@ -2004,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:
@@ -2071,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;
diff --git a/cmdparse.c b/cmdparse.c
index a6f1efa..08fc6dd 100644
--- a/cmdparse.c
+++ b/cmdparse.c
@@ -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) {
diff --git a/cmdparse.h b/cmdparse.h
index e62c0ad..3d18ade 100644
--- a/cmdparse.h
+++ b/cmdparse.h
@@ -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 */
diff --git a/conf.c b/conf.c
index 46a765d..a83d937 100644
--- a/conf.c
+++ b/conf.c
@@ -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
-
-static NTP_Source ntp_sources[MAX_NTP_SOURCES];
-static int n_ntp_sources = 0;
+/* Array of NTP_Source */
+static ARR_Instance ntp_sources;
-#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)
- return;
+ source.type = type;
+ source.pool = pool;
+ status = CPS_ParseNTPSourceAdd(line, &source.params);
- 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;
+ if (status != CPS_Success) {
+ CPS_StatusToString(status, str, sizeof (str));
+ other_parse_error(str);
+ return;
}
+
+ 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,16 +833,11 @@ 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");
- }
}
}
}
@@ -793,6 +845,23 @@ parse_initstepslew(char *line)
/* ================================================== */
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)
{
check_number_of_args(line, 1);
@@ -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);
- }
+ 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();
}
- broadcasts[n_broadcasts].addr = ip;
- broadcasts[n_broadcasts].port = port;
- broadcasts[n_broadcasts].interval = interval;
- ++n_broadcasts;
+ 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)
+{
+ *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_file;
+ *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);
}
/* ================================================== */
diff --git a/conf.h b/conf.h
index 2f9db00..ec08ded 100644
--- a/conf.h
+++ b/conf.h
@@ -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);
diff --git a/configure b/configure
index e82d1dd..d069c65 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/contrib/DNSchrony/COPYING b/contrib/DNSchrony/COPYING
deleted file mode 100644
index d511905..0000000
--- a/contrib/DNSchrony/COPYING
+++ /dev/null
@@ -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.
diff --git a/contrib/DNSchrony/DNSchrony.pl b/contrib/DNSchrony/DNSchrony.pl
deleted file mode 100755
index 57bf686..0000000
--- a/contrib/DNSchrony/DNSchrony.pl
+++ /dev/null
@@ -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);
-
-}
diff --git a/contrib/DNSchrony/DNSchronyADD b/contrib/DNSchrony/DNSchronyADD
deleted file mode 100755
index fc9858b..0000000
--- a/contrib/DNSchrony/DNSchronyADD
+++ /dev/null
@@ -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"
diff --git a/contrib/DNSchrony/DNSchronyDELETE b/contrib/DNSchrony/DNSchronyDELETE
deleted file mode 100755
index e443c9b..0000000
--- a/contrib/DNSchrony/DNSchronyDELETE
+++ /dev/null
@@ -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
diff --git a/contrib/DNSchrony/DNSchronyUPDATE b/contrib/DNSchrony/DNSchronyUPDATE
deleted file mode 100755
index 14cbceb..0000000
--- a/contrib/DNSchrony/DNSchronyUPDATE
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/bash
-
-# $1 is chrony password.
-
-
-CHRONYPASSWORD=$1 \
-/usr/local/bin/DNSchrony.pl -ulS
diff --git a/contrib/DNSchrony/README b/contrib/DNSchrony/README
deleted file mode 100644
index 05f45b5..0000000
--- a/contrib/DNSchrony/README
+++ /dev/null
@@ -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
diff --git a/contrib/DNSchrony/ip-up.local b/contrib/DNSchrony/ip-up.local
deleted file mode 100644
index 34f6e76..0000000
--- a/contrib/DNSchrony/ip-up.local
+++ /dev/null
@@ -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
diff --git a/examples/chrony.conf.example1 b/examples/chrony.conf.example1
new file mode 100644
index 0000000..f749534
--- /dev/null
+++ b/examples/chrony.conf.example1
@@ -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
diff --git a/examples/chrony.conf.example2 b/examples/chrony.conf.example2
index 56ab0a3..7c61b0a 100644
--- a/examples/chrony.conf.example2
+++ b/examples/chrony.conf.example2
@@ -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
diff --git a/examples/chrony.conf.example b/examples/chrony.conf.example3
index 256e414..9f2bbe5 100644
--- a/examples/chrony.conf.example
+++ b/examples/chrony.conf.example3
@@ -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
diff --git a/examples/chrony.spec b/examples/chrony.spec
index b7f368a..fa8ae33 100644
--- a/examples/chrony.spec
+++ b/examples/chrony.spec
@@ -1,4 +1,4 @@
-%global chrony_version 1.31.1
+%global chrony_version 2.1.1
%if 0%(echo %{chrony_version} | grep -q pre && echo 1)
%global prerelease %(echo %{chrony_version} | sed 's/.*-//')
%endif
@@ -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
diff --git a/hash.h b/hash.h
index f73f59d..185da66 100644
--- a/hash.h
+++ b/hash.h
@@ -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
diff --git a/hash_intmd5.c b/hash_intmd5.c
index 90b3bff..64e0b9c 100644
--- a/hash_intmd5.c
+++ b/hash_intmd5.c
@@ -62,3 +62,8 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
return 16;
}
+
+void
+HSH_Finalise(void)
+{
+}
diff --git a/hash_nss.c b/hash_nss.c
index a6a3c81..6e62304 100644
--- a/hash_nss.c
+++ b/hash_nss.c
@@ -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);
+}
diff --git a/hash_tomcrypt.c b/hash_tomcrypt.c
index 82c4d1c..db2f9f0 100644
--- a/hash_tomcrypt.c
+++ b/hash_tomcrypt.c
@@ -114,3 +114,8 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
return len;
}
+
+void
+HSH_Finalise(void)
+{
+}
diff --git a/keys.c b/keys.c
index 9025fea..fcd1974 100644
--- a/keys.c
+++ b/keys.c
@@ -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);
}
diff --git a/keys.h b/keys.h
index 9ba30c1..58f28cb 100644
--- a/keys.h
+++ b/keys.h
@@ -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 */
diff --git a/local.c b/local.c
index 5a3fb43..848cc3e 100644
--- a/local.c
+++ b/local.c
@@ -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;
}
/* ================================================== */
@@ -499,6 +557,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)
{
struct timeval raw, cooked;
@@ -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);
+ }
+}
+
+/* ================================================== */
diff --git a/local.h b/local.h
index aff9004..0dfdd73 100644
--- a/local.h
+++ b/local.h
@@ -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 */
diff --git a/localp.h b/localp.h
index ce92f1c..5f99309 100644
--- a/localp.h
+++ b/localp.h
@@ -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 */
diff --git a/logging.c b/logging.c
index 3ba71fc..2aff130 100644
--- a/logging.c
+++ b/logging.c
@@ -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;
}
}
diff --git a/logging.h b/logging.h
index 1b8236d..b4b4d18 100644
--- a/logging.h
+++ b/logging.h
@@ -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 */
diff --git a/main.c b/main.c
index 868cb7f..393b12e 100644
--- a/main.c
+++ b/main.c
@@ -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;
diff --git a/manual.c b/manual.c
index c286ce8..da2ed92 100644
--- a/manual.c
+++ b/manual.c
@@ -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 */
@@ -259,6 +271,14 @@ MNL_Reset(void)
}
/* ================================================== */
+
+int
+MNL_IsEnabled(void)
+{
+ return enabled;
+}
+
+/* ================================================== */
/* Generate report data for the REQ_MANUAL_LIST command/monitoring
protocol */
diff --git a/manual.h b/manual.h
index bd49b98..bf0c72a 100644
--- a/manual.h
+++ b/manual.h
@@ -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);
diff --git a/memory.c b/memory.c
new file mode 100644
index 0000000..7ad27d4
--- /dev/null
+++ b/memory.c
@@ -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;
+}
diff --git a/memory.h b/memory.h
index 5c65272..3ec0f04 100644
--- a/memory.h
+++ b/memory.h
@@ -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 */
diff --git a/mkdirpp.c b/mkdirpp.c
index 88e29da..ed4b23d 100644
--- a/mkdirpp.c
+++ b/mkdirpp.c
@@ -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;
}
diff --git a/nameserv.c b/nameserv.c
index f8a4b63..bb9309e 100644
--- a/nameserv.c
+++ b/nameserv.c
@@ -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;
diff --git a/nameserv.h b/nameserv.h
index 3980c1b..341a609 100644
--- a/nameserv.h
+++ b/nameserv.h
@@ -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);
diff --git a/nameserv_async.c b/nameserv_async.c
index 3ea187f..1ceeb28 100644
--- a/nameserv_async.c
+++ b/nameserv_async.c
@@ -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
diff --git a/nameserv_async.h b/nameserv_async.h
index 5c1704e..cea2d82 100644
--- a/nameserv_async.h
+++ b/nameserv_async.h
@@ -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
diff --git a/ntp.h b/ntp.h
index 6ae7bd8..5a377ef 100644
--- a/ntp.h
+++ b/ntp.h
@@ -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;
- NTP_int32 auth_keyid;
- uint8_t auth_data[MAX_NTP_AUTH_DATA_LEN];
-} NTP_Packet;
-/* We have to declare a buffer type to hold a datagram read from the
- network. Even though we won't be using them (yet?!), this must be
- large enough to hold NTP control messages. */
+ /* Optional extension fields, we don't send packets with them yet */
+ /* uint8_t extensions[] */
-/* 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). */
+ /* Optional message authentication code (MAC) */
+ NTP_int32 auth_keyid;
+ uint8_t auth_data[NTP_MAX_MAC_LENGTH];
+} NTP_Packet;
-#define MAX_NTP_MESSAGE_SIZE (468+12+16+4)
+#define NTP_NORMAL_PACKET_LENGTH (int)offsetof(NTP_Packet, auth_keyid)
-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;
-
-#define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
+ uint8_t extensions[NTP_MAX_EXTENSIONS_LENGTH];
+} NTP_Receive_Buffer;
+
+/* 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 */
diff --git a/ntp_core.c b/ntp_core.c
index e654c88..b477666 100644
--- a/ntp_core.c
+++ b/ntp_core.c
@@ -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,12 +29,14 @@
#include "sysincl.h"
+#include "array.h"
#include "ntp_core.h"
#include "ntp_io.h"
#include "memory.h"
#include "sched.h"
#include "reference.h"
#include "local.h"
+#include "smooth.h"
#include "sources.h"
#include "util.h"
#include "conf.h"
@@ -104,6 +106,8 @@ struct NCR_Instance_Record {
int poll_target; /* Target number of sourcestats samples */
+ int version; /* Version set in packets for server/peer */
+
double poll_score; /* Score of current local poll */
double max_delay; /* Maximum round-trip delay to the
@@ -111,7 +115,7 @@ struct NCR_Instance_Record {
use the sample for generating
statistics from */
- double max_delay_ratio; /* Largest ratio of delta /
+ double max_delay_ratio; /* Largest ratio of delay /
min_delay_in_register that we can
tolerate. */
@@ -123,7 +127,7 @@ struct NCR_Instance_Record {
the association is symmetric). Note
: we don't authenticate if we can't
find the key in our database. */
- unsigned long auth_key_id; /* The ID of the authentication key to
+ uint32_t auth_key_id; /* The ID of the authentication key to
use. */
/* Count of how many packets we have transmitted since last successful
@@ -166,6 +170,15 @@ struct NCR_Instance_Record {
};
+typedef struct {
+ NTP_Remote_Address addr;
+ NTP_Local_Address local_addr;
+ int interval;
+} BroadcastDestination;
+
+/* Array of BroadcastDestination */
+static ARR_Instance broadcasts;
+
/* ================================================== */
/* Initial delay period before first packet is transmitted (in seconds) */
#define INITIAL_DELAY 0.2
@@ -194,35 +207,35 @@ struct NCR_Instance_Record {
/* Time to wait after sending packet to 'warm up' link */
#define WARM_UP_DELAY 4.0
-/* The NTP protocol version that we support */
-#define NTP_VERSION 3
-
/* Compatible NTP protocol versions */
-#define NTP_MAX_COMPAT_VERSION 4
+#define NTP_MAX_COMPAT_VERSION NTP_VERSION
#define NTP_MIN_COMPAT_VERSION 1
-/* Maximum allowed dispersion - as defined in RFC1305 (16 seconds) */
+/* Maximum allowed dispersion - as defined in RFC 5905 (16 seconds) */
#define NTP_MAX_DISPERSION 16.0
-/* Maximum allowed age of a reference to be supplied to a client (1 day) */
-#define NTP_MAXAGE 86400
-
-/* Maximum allowed stratum */
-#define NTP_MAX_STRATUM 15
-
-/* INVALID or Unkown stratum from external server as per the NTP 4 docs */
+/* Invalid stratum number */
#define NTP_INVALID_STRATUM 0
-/* Minimum allowed poll interval */
+/* Minimum and maximum allowed poll interval */
#define MIN_POLL 0
+#define MAX_POLL 24
+
+/* Kiss-o'-Death codes */
+#define KOD_RATE 0x52415445UL /* RATE */
/* Maximum poll interval set by KoD RATE */
#define MAX_KOD_RATE_POLL SRC_DEFAULT_MAXPOLL
-#define INVALID_SOCK_FD -1
+/* Invalid socket, different from the one in ntp_io.c */
+#define INVALID_SOCK_FD -2
/* ================================================== */
+/* Server IPv4/IPv6 sockets */
+static int server_sock_fd4;
+static int server_sock_fd6;
+
static ADF_AuthTable access_auth_table;
/* ================================================== */
@@ -303,10 +316,15 @@ NCR_Initialise(void)
do_time_checks();
logfileid = CNF_GetLogMeasurements() ? LOG_FileOpen("measurements",
- " Date (UTC) Time IP Address L St 1234 abc 5678 LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
+ " Date (UTC) Time IP Address L St 123 567 ABCD LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
: -1;
access_auth_table = ADF_CreateTable();
+ broadcasts = ARR_CreateInstance(sizeof (BroadcastDestination));
+
+ /* Server socket will be opened when access is allowed */
+ server_sock_fd4 = INVALID_SOCK_FD;
+ server_sock_fd6 = INVALID_SOCK_FD;
}
/* ================================================== */
@@ -314,8 +332,18 @@ NCR_Initialise(void)
void
NCR_Finalise(void)
{
- ADF_DestroyTable(access_auth_table);
+ unsigned int i;
+ if (server_sock_fd4 != INVALID_SOCK_FD)
+ NIO_CloseServerSocket(server_sock_fd4);
+ if (server_sock_fd6 != INVALID_SOCK_FD)
+ NIO_CloseServerSocket(server_sock_fd6);
+
+ for (i = 0; i < ARR_GetSize(broadcasts); i++)
+ NIO_CloseServerSocket(((BroadcastDestination *)ARR_GetElement(broadcasts, i))->local_addr.sock_fd);
+
+ ARR_DestroyInstance(broadcasts);
+ ADF_DestroyTable(access_auth_table);
}
/* ================================================== */
@@ -408,7 +436,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
result->mode = MODE_CLIENT;
break;
case NTP_PEER:
- result->local_addr.sock_fd = NIO_GetServerSocket(remote_addr);
+ result->local_addr.sock_fd = NIO_OpenServerSocket(remote_addr);
result->mode = MODE_ACTIVE;
break;
default:
@@ -418,13 +446,19 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
result->minpoll = params->minpoll;
if (result->minpoll < MIN_POLL)
result->minpoll = SRC_DEFAULT_MINPOLL;
+ else if (result->minpoll > MAX_POLL)
+ result->minpoll = MAX_POLL;
result->maxpoll = params->maxpoll;
if (result->maxpoll < MIN_POLL)
result->maxpoll = SRC_DEFAULT_MAXPOLL;
+ else if (result->maxpoll > MAX_POLL)
+ result->maxpoll = MAX_POLL;
if (result->maxpoll < result->minpoll)
result->maxpoll = result->minpoll;
result->min_stratum = params->min_stratum;
+ if (result->min_stratum >= NTP_MAX_STRATUM)
+ result->min_stratum = NTP_MAX_STRATUM - 1;
result->presend_minpoll = params->presend_minpoll;
result->max_delay = params->max_delay;
@@ -433,20 +467,29 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
result->auto_offline = params->auto_offline;
result->poll_target = params->poll_target;
+ result->version = params->version;
+ if (result->version < NTP_MIN_COMPAT_VERSION)
+ result->version = NTP_MIN_COMPAT_VERSION;
+ else if (result->version > NTP_VERSION)
+ result->version = NTP_VERSION;
+
if (params->authkey == INACTIVE_AUTHKEY) {
result->do_auth = 0;
- result->auth_key_id = 0UL;
+ result->auth_key_id = 0;
} else {
result->do_auth = 1;
result->auth_key_id = params->authkey;
if (!KEY_KeyKnown(result->auth_key_id)) {
- LOG(LOGS_WARN, LOGF_NtpCore, "Source %s added with unknown key %lu",
+ LOG(LOGS_WARN, LOGF_NtpCore, "Source %s added with unknown key %"PRIu32,
UTI_IPToString(&result->remote_addr.ip_addr), result->auth_key_id);
}
}
/* Create a source instance for this NTP source */
- result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr), SRC_NTP, params->sel_option, &result->remote_addr.ip_addr);
+ result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr),
+ SRC_NTP, params->sel_option,
+ &result->remote_addr.ip_addr,
+ params->min_samples, params->max_samples);
result->timer_running = 0;
result->timeout_id = 0;
@@ -472,6 +515,9 @@ NCR_DestroyInstance(NCR_Instance instance)
if (instance->opmode != MD_OFFLINE)
take_offline(instance);
+ if (instance->mode == MODE_ACTIVE)
+ NIO_CloseServerSocket(instance->local_addr.sock_fd);
+
/* This will destroy the source instance inside the
structure, which will cause reselection if this was the
synchronising source etc. */
@@ -523,11 +569,24 @@ NCR_ResetInstance(NCR_Instance instance)
/* ================================================== */
-static int
-check_packet_auth(NTP_Packet *pkt, unsigned long keyid, int auth_len)
+void
+NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr)
{
- return KEY_CheckAuth(keyid, (void *)pkt, offsetof(NTP_Packet, auth_keyid),
- (void *)&(pkt->auth_data), auth_len);
+ inst->remote_addr = *remote_addr;
+ inst->tx_count = 0;
+ inst->presend_done = 0;
+
+ if (inst->mode == MODE_CLIENT)
+ close_client_socket(inst);
+ else {
+ NIO_CloseServerSocket(inst->local_addr.sock_fd);
+ inst->local_addr.sock_fd = NIO_OpenServerSocket(remote_addr);
+ }
+
+ /* Update the reference ID and reset the source/sourcestats instances */
+ SRC_SetRefid(inst->source, UTI_IPToRefid(&remote_addr->ip_addr),
+ &inst->remote_addr.ip_addr);
+ SRC_ResetInstance(inst->source);
}
/* ================================================== */
@@ -686,7 +745,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
int my_poll, /* The log2 of the local poll interval */
int version, /* The NTP version to be set in the packet */
int do_auth, /* Boolean indicating whether to authenticate the packet or not */
- unsigned long key_id, /* The authentication key ID */
+ uint32_t key_id, /* The authentication key ID */
NTP_int64 *orig_ts, /* Originate timestamp (from received packet) */
struct timeval *local_rx, /* Local time request packet was received */
struct timeval *local_tx, /* RESULT : Time this reply
@@ -703,15 +762,15 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
)
{
NTP_Packet message;
- int leap, ret;
- struct timeval local_transmit;
+ int leap, auth_len, length, ret;
+ struct timeval local_receive, local_transmit;
/* Parameters read from reference module */
- int are_we_synchronised, our_stratum;
+ int are_we_synchronised, our_stratum, smooth_time;
NTP_Leap leap_status;
uint32_t our_ref_id, ts_fuzz;
struct timeval our_ref_time;
- double our_root_delay, our_root_dispersion;
+ double our_root_delay, our_root_dispersion, smooth_offset;
/* Don't reply with version higher than ours */
if (version > NTP_VERSION) {
@@ -728,6 +787,28 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
&our_ref_id, &our_ref_time,
&our_root_delay, &our_root_dispersion);
+ /* Get current smoothing offset when sending packet to a client */
+ if (SMT_IsEnabled() && (my_mode == MODE_SERVER || my_mode == MODE_BROADCAST)) {
+ smooth_offset = SMT_GetOffset(&local_transmit);
+ smooth_time = fabs(smooth_offset) > LCL_GetSysPrecisionAsQuantum();
+
+ /* Suppress leap second when smoothing and slew mode are enabled */
+ if (REF_GetLeapMode() == REF_LeapModeSlew &&
+ (leap_status == LEAP_InsertSecond || leap_status == LEAP_DeleteSecond))
+ leap_status = LEAP_Normal;
+ } else {
+ smooth_time = 0;
+ smooth_offset = 0.0;
+ }
+
+ if (smooth_time) {
+ our_ref_id = NTP_REFID_SMOOTH;
+ UTI_AddDoubleToTimeval(&our_ref_time, smooth_offset, &our_ref_time);
+ UTI_AddDoubleToTimeval(local_rx, smooth_offset, &local_receive);
+ } else {
+ local_receive = *local_rx;
+ }
+
if (are_we_synchronised) {
leap = (int) leap_status;
} else {
@@ -735,11 +816,11 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
}
/* Generate transmit packet */
- message.lvm = ((leap << 6) &0xc0) | ((version << 3) & 0x38) | (my_mode & 0x07);
- if (our_stratum <= NTP_MAX_STRATUM) {
+ message.lvm = NTP_LVM(leap, version, my_mode);
+ /* Stratum 16 and larger are invalid */
+ if (our_stratum < NTP_MAX_STRATUM) {
message.stratum = our_stratum;
} else {
- /* (WGU) to handle NTP "Invalid" stratum as per the NTP V4 documents. */
message.stratum = NTP_INVALID_STRATUM;
}
@@ -751,9 +832,10 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
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);
+ message.reference_id = htonl(our_ref_id);
/* Now fill in timestamps */
+
UTI_TimevalToInt64(&our_ref_time, &message.reference_ts, 0);
/* Originate - this comes from the last packet the source sent us */
@@ -763,7 +845,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
This timestamp will have been adjusted so that it will now look to
the source like we have been running on our latest estimate of
frequency all along */
- UTI_TimevalToInt64(local_rx, &message.receive_ts, 0);
+ UTI_TimevalToInt64(&local_receive, &message.receive_ts, 0);
/* Prepare random bits which will be added to the transmit timestamp. */
ts_fuzz = UTI_GetNTPTsFuzz(message.precision);
@@ -773,9 +855,13 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
from the source we're sending to now. */
LCL_ReadCookedTime(&local_transmit, NULL);
+ if (smooth_time)
+ UTI_AddDoubleToTimeval(&local_transmit, smooth_offset, &local_transmit);
+
+ length = NTP_NORMAL_PACKET_LENGTH;
+
/* Authenticate */
- if (do_auth) {
- int auth_len;
+ if (do_auth && key_id) {
/* Pre-compensate the transmit time by approx. how long it will
take to generate the authentication data. */
local_transmit.tv_usec += KEY_GetAuthDelay(key_id);
@@ -787,19 +873,24 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
(unsigned char *)&message.auth_data, sizeof (message.auth_data));
if (auth_len > 0) {
message.auth_keyid = htonl(key_id);
- ret = NIO_SendAuthenticatedPacket(&message, where_to, from,
- sizeof (message.auth_keyid) + auth_len);
+ length += sizeof (message.auth_keyid) + auth_len;
} else {
DEBUG_LOG(LOGF_NtpCore,
- "Could not generate auth data with key %lu to send packet",
+ "Could not generate auth data with key %"PRIu32" to send packet",
key_id);
return 0;
}
} else {
+ if (do_auth) {
+ /* Zero key ID means crypto-NAK, append only the ID without any data */
+ message.auth_keyid = 0;
+ length += sizeof (message.auth_keyid);
+ }
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts, ts_fuzz);
- ret = NIO_SendNormalPacket(&message, where_to, from);
}
+ ret = NIO_SendPacket(&message, where_to, from, length);
+
if (local_tx) {
*local_tx = local_transmit;
}
@@ -835,6 +926,10 @@ transmit_timeout(void *arg)
break;
}
+ /* With auto_offline take the source offline on 2nd missed reply */
+ if (inst->auto_offline && inst->tx_count >= 2)
+ NCR_TakeSourceOffline(inst);
+
if (inst->opmode == MD_OFFLINE) {
return;
}
@@ -846,7 +941,7 @@ transmit_timeout(void *arg)
if (inst->mode == MODE_CLIENT) {
close_client_socket(inst);
assert(inst->local_addr.sock_fd == INVALID_SOCK_FD);
- inst->local_addr.sock_fd = NIO_GetClientSocket(&inst->remote_addr);
+ inst->local_addr.sock_fd = NIO_OpenClientSocket(&inst->remote_addr);
}
/* Check whether we need to 'warm up' the link to the other end by
@@ -860,7 +955,7 @@ transmit_timeout(void *arg)
/* Send a client packet, don't store the local tx values
as the reply will be ignored */
- transmit_packet(MODE_CLIENT, inst->local_poll, NTP_VERSION, 0, 0,
+ transmit_packet(MODE_CLIENT, inst->local_poll, inst->version, 0, 0,
&inst->remote_orig, &inst->local_rx, NULL, NULL,
&inst->remote_addr, &inst->local_addr);
@@ -875,7 +970,7 @@ transmit_timeout(void *arg)
inst->presend_done = 0; /* Reset for next time */
sent = transmit_packet(inst->mode, inst->local_poll,
- NTP_VERSION,
+ inst->version,
inst->do_auth, inst->auth_key_id,
&inst->remote_orig,
&inst->local_rx, &inst->local_tx, &inst->local_ntp_tx,
@@ -896,10 +991,6 @@ transmit_timeout(void *arg)
}
SRC_UpdateReachability(inst->source, 0);
-
- if (inst->auto_offline && inst->tx_count >= 3) {
- NCR_TakeSourceOffline(inst);
- }
}
switch (inst->opmode) {
@@ -922,49 +1013,116 @@ transmit_timeout(void *arg)
/* ================================================== */
-static void
-receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst, int auth_len)
+static int
+check_packet_format(NTP_Packet *message, int length)
+{
+ int version;
+
+ /* Check version and length */
+
+ version = NTP_LVM_TO_VERSION(message->lvm);
+ if (version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) {
+ DEBUG_LOG(LOGF_NtpCore, "NTP packet has invalid version %d", version);
+ return 0;
+ }
+
+ if (length < NTP_NORMAL_PACKET_LENGTH || (unsigned int)length % 4) {
+ DEBUG_LOG(LOGF_NtpCore, "NTP packet has invalid length %d", length);
+ return 0;
+ }
+
+ /* We can't reliably check the packet for invalid extension fields as we
+ support MACs longer than the shortest valid extension field */
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+check_packet_auth(NTP_Packet *pkt, int length, int *has_auth, uint32_t *key_id)
+{
+ int i, remainder, ext_length;
+ unsigned char *data;
+ uint32_t id;
+
+ /* Go through extension fields and see if there is a valid MAC */
+
+ i = NTP_NORMAL_PACKET_LENGTH;
+ data = (void *)pkt;
+
+ while (1) {
+ remainder = length - i;
+
+ /* Check if the remaining data is a valid MAC. This needs to be done
+ before trying to parse it as an extension field, because we support
+ MACs longer than the shortest valid extension field. */
+ if (remainder >= NTP_MIN_MAC_LENGTH && remainder <= NTP_MAX_MAC_LENGTH) {
+ id = ntohl(*(uint32_t *)(data + i));
+ if (KEY_CheckAuth(id, (void *)pkt, i, (void *)(data + i + 4),
+ remainder - 4)) {
+ if (key_id)
+ *key_id = id;
+ if (has_auth)
+ *has_auth = 1;
+ return 1;
+ }
+ }
+
+ /* Check if this is a valid field extension. They consist of 16-bit type,
+ 16-bit length of the whole field aligned to 32 bits and data. */
+ if (remainder >= NTP_MIN_EXTENSION_LENGTH) {
+ ext_length = ntohs(*(uint16_t *)(data + i + 2));
+ if (ext_length >= NTP_MIN_EXTENSION_LENGTH &&
+ ext_length <= remainder && ext_length % 4 == 0) {
+ i += ext_length;
+ continue;
+ }
+ }
+
+ /* Invalid or missing MAC, or format error */
+ break;
+ }
+
+ /* This is not 100% reliable as a MAC could fail to authenticate and could
+ pass as an extension field, leaving reminder smaller than the minimum MAC
+ length. Not a big problem, at worst we won't reply with a crypto-NAK. */
+ if (has_auth)
+ *has_auth = remainder >= NTP_MIN_MAC_LENGTH;
+
+ return 0;
+}
+
+/* ================================================== */
+
+static int
+receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst, NTP_Local_Address *local_addr, int length)
{
int pkt_leap;
- int source_is_synchronized;
+ uint32_t pkt_refid;
double pkt_root_delay;
double pkt_root_dispersion;
- unsigned long auth_key_id;
-
/* The local time to which the (offset, delay, dispersion) triple will
be taken to relate. For client/server operation this is practically
the same as either the transmit or receive time. The difference comes
- in symmetric active mode, when the receive may come minutes after the transmit, and this time
- will be midway between the two */
+ in symmetric active mode, when the receive may come minutes after the
+ transmit, and this time will be midway between the two */
struct timeval sample_time;
- /* The estimated offset (nomenclature from RFC1305 section 3.4.4).
- In seconds, a positive value indicates that the local clock is
- SLOW of the remote source and a negative value indicates that the local
- clock is FAST of the remote source. */
- double theta;
-
- /* The estimated round delay in seconds */
- double delta;
-
- /* The estimated peer dispersion in seconds */
- double epsilon;
-
- /* The estimated peer distance in seconds */
- double peer_distance;
+ /* The estimated offset in seconds, a positive value indicates that the local
+ clock is SLOW of the remote source and a negative value indicates that the
+ local clock is FAST of the remote source */
+ double offset;
- /* The total root delay */
- double root_delay;
+ /* The estimated peer delay, dispersion and distance */
+ double delay, dispersion, distance;
- /* The total root dispersion */
- double root_dispersion;
+ /* The total root delay and dispersion */
+ double root_delay, root_dispersion;
- /* The skew relative to the remote source */
- double skew;
-
- /* The estimated skew relative to the remote source. */
- double source_freq_lo, source_freq_hi;
+ /* The skew and estimated frequency offset relative to the remote source */
+ double skew, source_freq_lo, source_freq_hi;
/* These are the timeval equivalents of the remote epochs */
struct timeval remote_receive_tv, remote_transmit_tv;
@@ -972,87 +1130,111 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
struct timeval local_average, remote_average;
double local_interval, remote_interval;
- int test1, test2, test3, test4, test5, test6, test7, test7i, test7ii, test8;
-
- int test4a, test4b, test4c;
-
- /* In the words of section 3.4.4 of RFC1305, valid_data means
- that the NTP protocol association with the peer/server is
- properly synchronised. valid_header means that the measurement
- obtained from the packet is suitable for use in synchronising
- our local clock. Wierd choice of terminology. */
+ /* RFC 5905 packet tests */
+ int test1, test2, test3, test5, test6, test7;
+ int valid_packet;
- int valid_data, valid_header;
- int good_data, good_header;
+ /* Additional tests */
+ int testA, testB, testC, testD;
+ int good_packet;
- /* Kiss-of-Death packets */
- int kod_rate = 0;
- int valid_kod;
+ /* Kiss-o'-Death codes */
+ int kod_rate;
- /* Variables used for doing logging */
- static char sync_stats[4] = {'N', '+', '-', '?'};
+ /* Characters used to print synchronisation status */
+ static const char sync_stats[4] = {'N', '+', '-', '?'};
/* The estimated offset predicted from previous samples. The
convention here is that positive means local clock FAST of
- reference, i.e. backwards to the way that 'theta' is defined. */
+ reference, i.e. backwards to the way that 'offset' is defined. */
double estimated_offset;
/* The absolute difference between the offset estimate and
measurement in seconds */
double error_in_estimate;
- double delay_time = 0;
- int requeue_transmit = 0;
- /* ==================== */
+ double delay_time, precision;
+ int requeue_transmit;
- pkt_leap = (message->lvm >> 6) & 0x3;
- if (pkt_leap == 0x3) {
- source_is_synchronized = 0;
- } else {
- source_is_synchronized = 1;
- }
+ /* ==================== */
+ pkt_leap = NTP_LVM_TO_LEAP(message->lvm);
+ pkt_refid = ntohl(message->reference_id);
pkt_root_delay = UTI_Int32ToDouble(message->root_delay);
pkt_root_dispersion = UTI_Int32ToDouble(message->root_dispersion);
- /* Perform packet validity tests */
-
- /* Test 1 requires that pkt.xmt != peer.org. This protects
- against receiving a duplicate packet */
-
- if ((message->transmit_ts.hi == inst->remote_orig.hi) &&
- (message->transmit_ts.lo == inst->remote_orig.lo)) {
- test1 = 0; /* Failed */
- } else {
- test1 = 1; /* Success */
- }
+ UTI_Int64ToTimeval(&message->receive_ts, &remote_receive_tv);
+ UTI_Int64ToTimeval(&message->transmit_ts, &remote_transmit_tv);
+ UTI_Int64ToTimeval(&message->reference_ts, &remote_reference_tv);
- /* Test 2 requires pkt.org == peer.xmt. This ensures the source
- is responding to the latest packet we sent to it. */
- if ((message->originate_ts.hi != inst->local_ntp_tx.hi) ||
- (message->originate_ts.lo != inst->local_ntp_tx.lo)) {
- test2 = 0; /* Failed */
- } else {
- test2 = 1; /* Success */
+ /* Check if the packet is valid per RFC 5905, section 8.
+ The test values are 1 when passed and 0 when failed. */
+
+ /* Test 1 checks for duplicate packet */
+ test1 = message->transmit_ts.hi != inst->remote_orig.hi ||
+ message->transmit_ts.lo != inst->remote_orig.lo;
+
+ /* Test 2 checks for bogus packet. This ensures the source is responding to
+ the latest packet we sent to it. */
+ test2 = message->originate_ts.hi == inst->local_ntp_tx.hi &&
+ message->originate_ts.lo == inst->local_ntp_tx.lo;
+
+ /* Test 3 checks for invalid timestamps. This can happen when the
+ association if not properly 'up'. */
+ test3 = (message->originate_ts.hi || message->originate_ts.lo) &&
+ (message->receive_ts.hi || message->receive_ts.lo) &&
+ (message->reference_ts.hi || message->reference_ts.lo) &&
+ (message->transmit_ts.hi || message->transmit_ts.lo);
+
+ /* Test 4 would check for denied access. It would always pass as this
+ function is called only for known sources. */
+
+ /* Test 5 checks for authentication failure. If we expect authenticated info
+ from this peer/server and the packet doesn't have it or the authentication
+ is bad, it's got to fail. If the peer or server sends us an authenticated
+ frame, but we're not bothered about whether he authenticates or not, just
+ ignore the test. */
+ test5 = inst->do_auth ? check_packet_auth(message, length, NULL, NULL) : 1;
+
+ /* Test 6 checks for unsynchronised server */
+ test6 = pkt_leap != LEAP_Unsynchronised &&
+ message->stratum < NTP_MAX_STRATUM &&
+ message->stratum != NTP_INVALID_STRATUM;
+
+ /* Test 7 checks for bad data. The root distance must be smaller than a
+ defined maximum and the transmit time must not be before the time of
+ the last synchronisation update. */
+ test7 = pkt_root_delay / 2.0 + pkt_root_dispersion < NTP_MAX_DISPERSION &&
+ UTI_CompareTimevals(&remote_reference_tv, &remote_transmit_tv) < 1;
+
+ /* The packet is considered valid if the tests above passed */
+ valid_packet = test1 && test2 && test3 && test5 && test6 && test7;
+
+ /* Check for Kiss-o'-Death codes */
+ kod_rate = 0;
+ if (test1 && test2 && test5 && pkt_leap == LEAP_Unsynchronised &&
+ message->stratum == NTP_INVALID_STRATUM) {
+ if (pkt_refid == KOD_RATE)
+ kod_rate = 1;
}
- /* Test 3 requires that pkt.org != 0 and pkt.rec != 0. If
- either of these are true it means the association is not properly
- 'up'. */
-
- if (((message->originate_ts.hi == 0) && (message->originate_ts.lo == 0)) ||
- ((message->receive_ts.hi == 0) && (message->receive_ts.lo == 0))) {
- test3 = 0; /* Failed */
- } else {
- test3 = 1; /* Success */
+ /* The transmit timestamp and local receive timestamp must not be saved when
+ the authentication test failed to prevent denial-of-service attacks on
+ symmetric associations using authentication */
+ if (test5) {
+ inst->remote_orig = message->transmit_ts;
+ inst->local_rx = *now;
}
- SRC_GetFrequencyRange(inst->source, &source_freq_lo, &source_freq_hi);
+ /* This protects against replay of the last packet we sent */
+ if (test2)
+ inst->local_ntp_tx.hi = inst->local_ntp_tx.lo = 0;
- UTI_Int64ToTimeval(&message->receive_ts, &remote_receive_tv);
- UTI_Int64ToTimeval(&message->transmit_ts, &remote_transmit_tv);
+ if (valid_packet) {
+ precision = LCL_GetSysPrecisionAsQuantum() +
+ UTI_Log2ToDouble(message->precision);
- if (test3) {
+ SRC_GetFrequencyRange(inst->source, &source_freq_lo, &source_freq_hi);
UTI_AverageDiffTimevals(&remote_receive_tv, &remote_transmit_tv,
&remote_average, &remote_interval);
@@ -1060,16 +1242,19 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
UTI_AverageDiffTimevals(&inst->local_tx, now,
&local_average, &local_interval);
- /* In our case, we work out 'delta' as the worst case delay,
+ /* In our case, we work out 'delay' as the worst case delay,
assuming worst case frequency error between us and the other
source */
+ delay = local_interval - remote_interval * (1.0 + source_freq_lo);
+
+ /* Clamp delay to avoid misleading results later */
+ delay = fabs(delay);
+ if (delay < precision)
+ delay = precision;
- delta = local_interval - remote_interval * (1.0 + source_freq_lo);
-
- /* Calculate theta. Following the NTP definition, this is negative
+ /* Calculate offset. Following the NTP definition, this is negative
if we are fast of the remote source. */
-
- UTI_DiffTimevalsToDouble(&theta, &remote_average, &local_average);
+ UTI_DiffTimevalsToDouble(&offset, &remote_average, &local_average);
/* We treat the time of the sample as being midway through the local
measurement period. An analysis assuming constant relative
@@ -1082,182 +1267,65 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
skew = (source_freq_hi - source_freq_lo) / 2.0;
/* and then calculate peer dispersion */
- epsilon = LCL_GetSysPrecisionAsQuantum() + now_err + skew * fabs(local_interval);
+ dispersion = precision + now_err + skew * fabs(local_interval);
+ /* Additional tests required to pass before accumulating the sample */
+
+ /* Test A requires that the round trip delay is less than an
+ administrator-defined value */
+ testA = delay <= inst->max_delay;
+
+ /* Test B requires that the ratio of the round trip delay to the
+ minimum one currently in the stats data register is less than an
+ administrator-defined value */
+ testB = inst->max_delay_ratio <= 1.0 ||
+ delay / SRC_MinRoundTripDelay(inst->source) <= inst->max_delay_ratio;
+
+ /* Test C requires that the ratio of the increase in delay from the minimum
+ one in the stats data register to the standard deviation of the offsets
+ in the register is less than an administrator-defined value or the
+ difference between measured offset and predicted offset is larger than
+ the increase in delay */
+ testC = SRC_IsGoodSample(inst->source, -offset, delay,
+ inst->max_delay_dev_ratio, LCL_GetMaxClockError(),
+ &sample_time);
+
+ /* Test D requires that the remote peer is not synchronised to us to
+ prevent a synchronisation loop */
+ testD = message->stratum <= 1 || pkt_refid != UTI_IPToRefid(&local_addr->ip_addr);
} else {
- /* If test3 failed, we probably can't calculate these quantities
- properly (e.g. for the first sample received in a peering
- connection). */
- theta = delta = epsilon = 0.0;
+ offset = delay = dispersion = 0.0;
sample_time = *now;
+ testA = testB = testC = testD = 0;
}
- peer_distance = epsilon + 0.5 * fabs(delta);
-
- /* Test 4 requires that the round trip delay to the source and the
- source (RFC1305 'peer') dispersion are less than a cutoff value */
-
- if ((fabs(delta) >= NTP_MAX_DISPERSION) ||
- (epsilon >= NTP_MAX_DISPERSION)) {
- test4 = 0; /* Failed */
- } else {
- test4 = 1; /* Success */
- }
-
- /* Test 4a (additional to RFC1305) requires that the round trip
- delay is less than an administrator-defined value */
-
- if (fabs(delta) > inst->max_delay) {
- test4a = 0; /* Failed */
- } else {
- test4a = 1; /* Success */
- }
-
- /* Test 4b (additional to RFC1305) requires that the ratio of the
- round trip delay to the minimum one currently in the stats data
- register is less than an administrator-defined value */
-
- if (inst->max_delay_ratio > 1.0 &&
- fabs(delta/SRC_MinRoundTripDelay(inst->source)) > inst->max_delay_ratio) {
- test4b = 0; /* Failed */
- } else {
- test4b = 1; /* Success */
- }
-
- /* Test 4c (additional to RFC1305) requires that the ratio of the
- increase in delay from the minimum one in the stats data register to
- the standard deviation of the offsets in the register is less than an
- administrator-defined value or the difference between measured offset
- and predicted offset is larger than the increase in delay */
- if (!SRC_IsGoodSample(inst->source, -theta, fabs(delta),
- inst->max_delay_dev_ratio, LCL_GetMaxClockError(), &sample_time)) {
- test4c = 0; /* Failed */
- } else {
- test4c = 1; /* Success */
- }
-
- /* Test 5 relates to authentication. */
- if (inst->do_auth) {
- if (auth_len > 0) {
- auth_key_id = ntohl(message->auth_keyid);
- test5 = check_packet_auth(message, auth_key_id, auth_len);
- } else {
- /* If we expect authenticated info from this peer/server and the packet
- doesn't have it, it's got to fail */
- test5 = 0;
- }
- } else {
- /* If the peer or server sends us an authenticated frame, but
- we're not bothered about whether he authenticates or not, just
- ignore the test. */
- test5 = 1;
- }
-
- /* Test 6 checks that (i) the remote clock is synchronised (ii) the
- transmit timestamp is not before the time it was synchronized (clearly
- bogus if it is), and (iii) that it was not synchronised too long ago
- */
- UTI_Int64ToTimeval(&message->reference_ts, &remote_reference_tv);
- if ((!source_is_synchronized) ||
- (UTI_CompareTimevals(&remote_reference_tv, &remote_transmit_tv) == 1) ||
- ((remote_reference_tv.tv_sec + NTP_MAXAGE - remote_transmit_tv.tv_sec) < 0)) {
- test6 = 0; /* Failed */
- } else {
- test6 = 1; /* Succeeded */
- }
-
- /* (WGU) Set stratum to greater than any valid if incoming is 0 */
- /* as per the NPT v4 documentation*/
- if (message->stratum <= NTP_INVALID_STRATUM) {
- message->stratum = NTP_MAX_STRATUM + 1;
- }
-
- /* Increase stratum to the configured minimum */
- if (message->stratum < inst->min_stratum) {
- message->stratum = inst->min_stratum;
- }
-
- /* Test 7i checks that the stratum in the packet is valid */
- if (message->stratum > NTP_MAX_STRATUM) {
- test7i = 0; /* Failed */
- } else {
- test7i = 1;
- }
-
- /* Test 7ii checks that the stratum in the packet is not higher than ours */
- if (message->stratum > REF_GetOurStratum()) {
- test7ii = 0; /* Failed */
- } else {
- test7ii = 1;
- }
-
- test7 = test7i && test7ii;
-
- /* Test 8 checks that the root delay and dispersion quoted in
- the packet are appropriate */
- if ((pkt_root_delay >= NTP_MAX_DISPERSION) ||
- (pkt_root_dispersion >= NTP_MAX_DISPERSION)) {
- test8 = 0; /* Failed */
- } else {
- test8 = 1;
- }
-
- /* Check for Kiss-of-Death */
- if (!test7i && !source_is_synchronized) {
- if (!memcmp(&message->reference_id, "RATE", 4))
- kod_rate = 1;
- }
-
- /* The transmit timestamp and local receive timestamp must not be saved when
- the authentication test failed to prevent denial-of-service attacks on
- symmetric associations using authentication */
- if (test5) {
- inst->remote_orig = message->transmit_ts;
- inst->local_rx = *now;
- }
-
- valid_kod = test1 && test2 && test5;
-
- valid_data = test1 && test2 && test3 && test4 && test4a && test4b;
- good_data = valid_data && test4c;
- valid_header = test5 && test6 && test7i && test8;
- good_header = valid_header && test7ii;
-
- root_delay = pkt_root_delay + fabs(delta);
- root_dispersion = pkt_root_dispersion + epsilon;
-
- DEBUG_LOG(LOGF_NtpCore, "lvm=%o stratum=%d poll=%d prec=%d",
- message->lvm, message->stratum, message->poll, message->precision);
- DEBUG_LOG(LOGF_NtpCore, "Root delay=%08x (%f), dispersion=%08x (%f)",
- message->root_delay, pkt_root_delay, message->root_dispersion, pkt_root_dispersion);
- DEBUG_LOG(LOGF_NtpCore, "Ref id=[%x], ref_time=%08x.%08x [%s]",
- ntohl(message->reference_id),
- message->reference_ts.hi, message->reference_ts.lo,
- UTI_TimestampToString(&message->reference_ts));
- DEBUG_LOG(LOGF_NtpCore, "Originate=%08x.%08x [%s]",
- message->originate_ts.hi, message->originate_ts.lo,
- UTI_TimestampToString(&message->originate_ts));
- DEBUG_LOG(LOGF_NtpCore, "Message receive=%08x.%08x [%s]",
- message->receive_ts.hi, message->receive_ts.lo,
- UTI_TimestampToString(&message->receive_ts));
-
- DEBUG_LOG(LOGF_NtpCore, "Transmit=%08x.%08x [%s]",
- message->transmit_ts.hi, message->transmit_ts.lo,
- UTI_TimestampToString(&message->transmit_ts));
-
- DEBUG_LOG(LOGF_NtpCore, "theta=%f delta=%f epsilon=%f root_delay=%f root_dispersion=%f",
- theta, delta, epsilon, root_delay, root_dispersion);
-
- DEBUG_LOG(LOGF_NtpCore, "test1=%d test2=%d test3=%d test4=%d valid_data=%d good_data=%d",
- test1, test2, test3, test4, valid_data, good_data);
-
- DEBUG_LOG(LOGF_NtpCore, "test5=%d test6=%d test7=%d test8=%d valid_header=%d good_header=%d",
- test5, test6, test7, test8, valid_header, good_header);
-
- DEBUG_LOG(LOGF_NtpCore, "kod_rate=%d valid_kod=%d", kod_rate, valid_kod);
+ /* The packet is considered good for synchronisation if
+ the additional tests passed */
+ good_packet = testA && testB && testC && testD;
+
+ root_delay = pkt_root_delay + delay;
+ root_dispersion = pkt_root_dispersion + dispersion;
+ distance = dispersion + 0.5 * delay;
+
+ DEBUG_LOG(LOGF_NtpCore, "NTP packet lvm=%o stratum=%d poll=%d prec=%d root_delay=%f root_disp=%f refid=%"PRIx32" [%s]",
+ message->lvm, message->stratum, message->poll, message->precision,
+ pkt_root_delay, pkt_root_dispersion, pkt_refid,
+ message->stratum == NTP_INVALID_STRATUM ? UTI_RefidToString(pkt_refid) : "");
+ DEBUG_LOG(LOGF_NtpCore, "reference=%s origin=%s receive=%s transmit=%s",
+ UTI_TimestampToString(&message->reference_ts),
+ UTI_TimestampToString(&message->originate_ts),
+ UTI_TimestampToString(&message->receive_ts),
+ UTI_TimestampToString(&message->transmit_ts));
+ DEBUG_LOG(LOGF_NtpCore, "offset=%f delay=%f dispersion=%f root_delay=%f root_dispersion=%f",
+ offset, delay, dispersion, root_delay, root_dispersion);
+ DEBUG_LOG(LOGF_NtpCore, "test123=%d%d%d test567=%d%d%d testABCD=%d%d%d%d kod_rate=%d valid=%d good=%d",
+ test1, test2, test3, test5, test6, test7, testA, testB, testC, testD,
+ kod_rate, valid_packet, good_packet);
+
+ requeue_transmit = 0;
/* Reduce polling rate if KoD RATE was received */
- if (kod_rate && valid_kod) {
+ if (kod_rate) {
if (message->poll > inst->minpoll) {
/* Set our minpoll to message poll, but use a reasonable maximum */
if (message->poll <= MAX_KOD_RATE_POLL)
@@ -1286,32 +1354,23 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
requeue_transmit = 1;
}
- if (valid_header && valid_data) {
+ if (valid_packet) {
inst->remote_poll = message->poll;
inst->remote_stratum = message->stratum;
inst->tx_count = 0;
SRC_UpdateReachability(inst->source, 1);
- /* Mark the source as suitable for synchronisation when both header and
- data are good, unmark when header is not good (i.e. the stratum is
- higher than ours) */
- if (good_header) {
- if (good_data) {
- SRC_SetSelectable(inst->source);
- }
- } else {
- SRC_UnsetSelectable(inst->source);
- }
-
- if (good_data) {
+ if (good_packet) {
/* Do this before we accumulate a new sample into the stats registers, obviously */
estimated_offset = SRC_PredictOffset(inst->source, &sample_time);
SRC_AccumulateSample(inst->source,
&sample_time,
- theta, fabs(delta), epsilon,
+ offset, delay, dispersion,
root_delay, root_dispersion,
- message->stratum, (NTP_Leap) pkt_leap);
+ message->stratum > inst->min_stratum ?
+ message->stratum : inst->min_stratum,
+ (NTP_Leap) pkt_leap);
SRC_SelectSource(inst->source);
@@ -1319,10 +1378,10 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
not even within +/- the peer distance of the peer, we are clearly
not tracking the peer at all well, so we back off the sampling
rate depending on just how bad the situation is. */
- error_in_estimate = fabs(-theta - estimated_offset);
+ error_in_estimate = fabs(-offset - estimated_offset);
/* Now update the polling interval */
- adjust_poll(inst, get_poll_adj(inst, error_in_estimate, peer_distance));
+ adjust_poll(inst, get_poll_adj(inst, error_in_estimate, distance));
/* If we're in burst mode, check whether the burst is completed and
revert to the previous mode */
@@ -1341,7 +1400,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
break;
}
} else {
- /* Slowly increase the polling interval if we can't get good_data */
+ /* Slowly increase the polling interval if we can't get good packet */
adjust_poll(inst, 0.1);
}
@@ -1368,119 +1427,78 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
/* Do measurement logging */
if (logfileid != -1) {
- LOG_FileWrite(logfileid, "%s %-15s %1c %2d %1d%1d%1d%1d %1d%1d%1d %1d%1d%1d%1d %2d %2d %4.2f %10.3e %10.3e %10.3e %10.3e %10.3e",
+ LOG_FileWrite(logfileid, "%s %-15s %1c %2d %1d%1d%1d %1d%1d%1d %1d%1d%1d%d %2d %2d %4.2f %10.3e %10.3e %10.3e %10.3e %10.3e",
UTI_TimeToLogForm(sample_time.tv_sec),
UTI_IPToString(&inst->remote_addr.ip_addr),
sync_stats[pkt_leap],
message->stratum,
- test1, test2, test3, test4,
- test4a, test4b, test4c,
- test5, test6, test7, test8,
+ test1, test2, test3, test5, test6, test7, testA, testB, testC, testD,
inst->local_poll, inst->remote_poll,
inst->poll_score,
- theta, delta, epsilon,
+ offset, delay, dispersion,
pkt_root_delay, pkt_root_dispersion);
}
+
+ return valid_packet;
}
/* ================================================== */
-/* From RFC1305, the standard handling of receive packets, depending
+/* From RFC 5905, the standard handling of received packets, depending
on the mode of the packet and of the source, is :
- Source mode>>>
- Packet
- mode active passive client server bcast
- vvv
-
- active recv pkt recv xmit xmit
- passive recv error recv error error
- client xmit xmit error xmit xmit
- server recv error recv error error
- bcast recv error recv error error
-
- We ignore broadcasts in this implementation - they create too many
- problems.
-
+ +------------------+---------------------------------------+
+ | | Packet Mode |
+ +------------------+-------+-------+-------+-------+-------+
+ | Association Mode | 1 | 2 | 3 | 4 | 5 |
+ +------------------+-------+-------+-------+-------+-------+
+ | No Association 0 | NEWPS | DSCRD | FXMIT | MANY | NEWBC |
+ | Symm. Active 1 | PROC | PROC | DSCRD | DSCRD | DSCRD |
+ | Symm. Passive 2 | PROC | ERR | DSCRD | DSCRD | DSCRD |
+ | Client 3 | DSCRD | DSCRD | DSCRD | PROC | DSCRD |
+ | Server 4 | DSCRD | DSCRD | DSCRD | DSCRD | DSCRD |
+ | Broadcast 5 | DSCRD | DSCRD | DSCRD | DSCRD | DSCRD |
+ | Bcast Client 6 | DSCRD | DSCRD | DSCRD | DSCRD | PROC |
+ +------------------+-------+-------+-------+-------+-------+
+
+ Association mode 0 is implemented in NCR_ProcessUnknown(), other modes
+ in NCR_ProcessKnown().
+
+ Broadcast, manycast and ephemeral symmetric passive associations are not
+ supported yet.
*/
/* ================================================== */
/* 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 */
-void
+int
NCR_ProcessKnown
(NTP_Packet *message, /* the received message */
struct timeval *now, /* timestamp at time of receipt */
double now_err,
NCR_Instance inst, /* the instance record for this peer/server */
- int sock_fd, /* the receiving socket */
+ NTP_Local_Address *local_addr, /* the receiving address */
int length /* the length of the received packet */
)
{
- int pkt_mode;
- int version;
- int auth_len;
-
- /* Make sure the packet was received by the sending socket */
- if (sock_fd != inst->local_addr.sock_fd) {
- DEBUG_LOG(LOGF_NtpCore,
- "Packet received by wrong socket %d (expected %d)",
- sock_fd, inst->local_addr.sock_fd);
- return;
- }
-
- /* Ignore packets from offline sources */
- if (inst->opmode == MD_OFFLINE || inst->tx_suspended) {
- return;
- }
+ int pkt_mode, proc_packet, proc_as_unknown, log_peer_access;
- /* Check version */
- version = (message->lvm >> 3) & 0x7;
- if (version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) {
- /* Ignore packet, but might want to log it */
- return;
- }
-
- /* Perform tests mentioned in RFC1305 to validate packet contents */
- pkt_mode = (message->lvm >> 0) & 0x7;
+ if (!check_packet_format(message, length))
+ return 0;
- /* Length of the authentication data, if any */
- auth_len = length - (NTP_NORMAL_PACKET_SIZE + sizeof (message->auth_keyid));
- if (auth_len < 0) {
- auth_len = 0;
- }
+ pkt_mode = NTP_LVM_TO_MODE(message->lvm);
+ proc_packet = 0;
+ proc_as_unknown = 0;
+ log_peer_access = 0;
/* Now, depending on the mode we decide what to do */
switch (pkt_mode) {
- case MODE_CLIENT:
- /* If message is client mode, we just respond with a server mode
- packet, regardless of what we think the remote machine is
- supposed to be. However, even though this is a configured
- peer or server, we still implement access restrictions on
- client mode operation.
-
- This is an extension to RFC1305, as we don't bother to check
- whether we are a client of the remote machine.
-
- This copes with the case for an isolated network where one
- machine is set by eye and is used as the master, with the
- other machines pointed at it. If the master goes down, we
- want to be able to reset its time at startup by relying on
- one of the secondaries to flywheel it. The behaviour coded here
- is required in the secondaries to make this possible. */
-
- NCR_ProcessUnknown(message, now, now_err,
- &inst->remote_addr, &inst->local_addr, length);
-
- break;
-
case MODE_ACTIVE:
-
- switch(inst->mode) {
+ switch (inst->mode) {
case MODE_ACTIVE:
/* Ordinary symmetric peering */
- CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
- receive_packet(message, now, now_err, inst, auth_len);
+ log_peer_access = 1;
+ proc_packet = 1;
break;
case MODE_PASSIVE:
/* In this software this case should not arise, we don't
@@ -1488,91 +1506,102 @@ NCR_ProcessKnown
break;
case MODE_CLIENT:
/* This is where we have the remote configured as a server and he has
- us configured as a peer - fair enough. */
- CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
- receive_packet(message, now, now_err, inst, auth_len);
- break;
- case MODE_SERVER:
- /* Nonsense - we can't have a preconfigured server */
- break;
- case MODE_BROADCAST:
- /* We don't handle broadcasts */
+ us configured as a peer, process as from an unknown source */
+ proc_as_unknown = 1;
break;
default:
- /* Obviously ignore */
+ /* Discard */
break;
}
-
break;
- case MODE_SERVER:
- /* Ignore presend reply */
- if (inst->presend_done)
- break;
-
- switch(inst->mode) {
+ case MODE_PASSIVE:
+ switch (inst->mode) {
case MODE_ACTIVE:
- /* Slightly bizarre combination, but we can still process it */
- CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
- receive_packet(message, now, now_err, inst, auth_len);
+ /* This would arise if we have the remote configured as a peer and
+ he does not have us configured */
+ log_peer_access = 1;
+ proc_packet = 1;
break;
case MODE_PASSIVE:
- /* We have no passive peers in this software */
- break;
- case MODE_CLIENT:
- /* Standard case where he's a server and we're the client */
- receive_packet(message, now, now_err, inst, auth_len);
- break;
- case MODE_SERVER:
- /* RFC1305 error condition. */
- break;
- case MODE_BROADCAST:
- /* RFC1305 error condition */
+ /* Error condition in RFC 5905 */
break;
default:
- /* Obviously ignore */
+ /* Discard */
break;
}
break;
- case MODE_PASSIVE:
+ case MODE_CLIENT:
+ /* If message is client mode, we just respond with a server mode
+ packet, regardless of what we think the remote machine is
+ supposed to be. However, even though this is a configured
+ peer or server, we still implement access restrictions on
+ client mode operation.
- switch(inst->mode) {
- case MODE_ACTIVE:
- /* This would arise if we have the remote configured as a peer and
- he does not have us configured */
- CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
- receive_packet(message, now, now_err, inst, auth_len);
- break;
- case MODE_PASSIVE:
- /* Error condition in RFC1305. Also, we can't have any
- non-transient PASSIVE sources in this version, we only
- allow configured peers! */
- break;
+ This copes with the case for an isolated network where one
+ machine is set by eye and is used as the master, with the
+ other machines pointed at it. If the master goes down, we
+ want to be able to reset its time at startup by relying on
+ one of the secondaries to flywheel it. The behaviour coded here
+ is required in the secondaries to make this possible. */
+
+ proc_as_unknown = 1;
+ break;
+
+ case MODE_SERVER:
+ /* Ignore presend reply */
+ if (inst->presend_done)
+ break;
+
+ switch (inst->mode) {
case MODE_CLIENT:
- /* This is a wierd combination - how could it arise? */
- receive_packet(message, now, now_err, inst, auth_len);
- break;
- case MODE_SERVER:
- /* Error condition in RFC1305 */
- break;
- case MODE_BROADCAST:
- /* Error condition in RFC1305 */
+ /* Standard case where he's a server and we're the client */
+ proc_packet = 1;
break;
default:
- /* Obviously ignore */
+ /* Discard */
break;
}
break;
case MODE_BROADCAST:
- /* Just ignore these, but might want to log them */
+ /* Just ignore these */
break;
default:
/* Obviously ignore */
break;
-
+ }
+
+ if (log_peer_access)
+ CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, now->tv_sec);
+
+ if (proc_packet) {
+ /* Check if the reply was received by the socket that sent the request */
+ if (local_addr->sock_fd != inst->local_addr.sock_fd) {
+ DEBUG_LOG(LOGF_NtpCore,
+ "Packet received by wrong socket %d (expected %d)",
+ local_addr->sock_fd, inst->local_addr.sock_fd);
+ return 0;
+ }
+
+ /* Ignore packets from offline sources */
+ if (inst->opmode == MD_OFFLINE || inst->tx_suspended) {
+ DEBUG_LOG(LOGF_NtpCore, "Packet from offline source");
+ return 0;
+ }
+
+ return receive_packet(message, now, now_err, inst, local_addr, length);
+ } else if (proc_as_unknown) {
+ NCR_ProcessUnknown(message, now, now_err, &inst->remote_addr,
+ local_addr, length);
+ /* It's not a reply to our request, don't return success */
+ return 0;
+ } else {
+ DEBUG_LOG(LOGF_NtpCore, "NTP packet discarded pkt_mode=%d our_mode=%d",
+ pkt_mode, inst->mode);
+ return 0;
}
}
@@ -1590,11 +1619,9 @@ NCR_ProcessUnknown
int length /* the length of the received packet */
)
{
- NTP_Mode his_mode;
- NTP_Mode my_mode;
- int my_poll, version;
- int valid_auth, auth_len;
- unsigned long key_id;
+ NTP_Mode pkt_mode, my_mode;
+ int has_auth, valid_auth;
+ uint32_t key_id;
/* Ignore the packet if it wasn't received by server socket */
if (!NIO_IsServerSocket(local_addr->sock_fd)) {
@@ -1603,66 +1630,52 @@ NCR_ProcessUnknown
return;
}
- /* Check version */
- version = (message->lvm >> 3) & 0x7;
- if (version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) {
- /* Ignore packet, but might want to log it */
+ if (!check_packet_format(message, length))
return;
- }
- if (ADF_IsAllowed(access_auth_table, &remote_addr->ip_addr)) {
+ if (!ADF_IsAllowed(access_auth_table, &remote_addr->ip_addr)) {
+ DEBUG_LOG(LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d",
+ UTI_IPToString(&remote_addr->ip_addr),
+ remote_addr->port);
+ return;
+ }
- his_mode = message->lvm & 0x07;
-
- if (his_mode == MODE_CLIENT) {
- /* We are server */
- my_mode = MODE_SERVER;
- CLG_LogNTPClientAccess(&remote_addr->ip_addr, (time_t) now->tv_sec);
+ pkt_mode = NTP_LVM_TO_MODE(message->lvm);
- } else if (his_mode == MODE_ACTIVE) {
+ switch (pkt_mode) {
+ case MODE_ACTIVE:
/* We are symmetric passive, even though we don't ever lock to him */
my_mode = MODE_PASSIVE;
- CLG_LogNTPPeerAccess(&remote_addr->ip_addr, (time_t) now->tv_sec);
-
- } else {
- my_mode = MODE_UNDEFINED;
- }
-
- /* If we can't determine a sensible mode to reply with, it means
- he has supplied a wierd mode in his request, so ignore it. */
-
- if (my_mode != MODE_UNDEFINED) {
- int do_auth = 0;
- auth_len = length - (NTP_NORMAL_PACKET_SIZE + sizeof (message->auth_keyid));
-
- if (auth_len > 0) {
- /* Only reply if we know the key and the packet authenticates
- properly. */
- key_id = ntohl(message->auth_keyid);
- do_auth = 1;
- valid_auth = check_packet_auth(message, key_id, auth_len);
- }
-
- if (!do_auth || valid_auth) {
- /* Reply with the same poll, the client may use it to control its poll */
- my_poll = message->poll;
-
- transmit_packet(my_mode, my_poll,
- version,
- do_auth, do_auth ? key_id : 0,
- &message->transmit_ts, /* Originate (for us) is the transmit time for the client */
- now, /* Time we received the packet */
- NULL, /* Don't care when we send reply, we aren't maintaining state about this client */
- NULL, /* Ditto */
- remote_addr,
- local_addr);
- }
- }
- } else {
- DEBUG_LOG(LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d",
- UTI_IPToString(&remote_addr->ip_addr),
- remote_addr->port);
+ CLG_LogNTPPeerAccess(&remote_addr->ip_addr, now->tv_sec);
+ break;
+ case MODE_CLIENT:
+ /* Reply with server packet */
+ my_mode = MODE_SERVER;
+ CLG_LogNTPClientAccess(&remote_addr->ip_addr, now->tv_sec);
+ break;
+ default:
+ /* Discard */
+ DEBUG_LOG(LOGF_NtpCore, "NTP packet discarded pkt_mode=%d", pkt_mode);
+ return;
}
+
+ /* Check if the packet includes MAC that authenticates properly */
+ valid_auth = check_packet_auth(message, length, &has_auth, &key_id);
+
+ /* If authentication failed, reply with crypto-NAK */
+ if (!valid_auth)
+ key_id = 0;
+
+ /* Send a reply.
+ - copy the poll value as the client may use it to control its polling
+ interval
+ - authenticate the packet if the request was authenticated
+ - originate timestamp is the client's transmit time
+ - don't save our transmit timestamp as we aren't maintaining state about
+ this client */
+ transmit_packet(my_mode, message->poll, NTP_LVM_TO_VERSION(message->lvm),
+ has_auth, key_id, &message->transmit_ts, now, NULL, NULL,
+ remote_addr, local_addr);
}
/* ================================================== */
@@ -1670,18 +1683,12 @@ NCR_ProcessUnknown
void
NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset)
{
- struct timeval prev;
double delta;
- prev = inst->local_rx;
+
if (inst->local_rx.tv_sec || inst->local_rx.tv_usec)
UTI_AdjustTimeval(&inst->local_rx, when, &inst->local_rx, &delta, dfreq, doffset);
- DEBUG_LOG(LOGF_NtpCore, "rx prev=[%s] new=[%s]",
- UTI_TimevalToString(&prev), UTI_TimevalToString(&inst->local_rx));
- prev = inst->local_tx;
if (inst->local_tx.tv_sec || inst->local_tx.tv_usec)
UTI_AdjustTimeval(&inst->local_tx, when, &inst->local_tx, &delta, dfreq, doffset);
- DEBUG_LOG(LOGF_NtpCore, "tx prev=[%s] new=[%s]",
- UTI_TimevalToString(&prev), UTI_TimevalToString(&inst->local_tx));
}
/* ================================================== */
@@ -1736,7 +1743,7 @@ NCR_TakeSourceOffline(NCR_Instance inst)
void
NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
{
- if (new_minpoll < MIN_POLL)
+ if (new_minpoll < MIN_POLL || new_minpoll > MAX_POLL)
return;
inst->minpoll = new_minpoll;
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new minpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_minpoll);
@@ -1749,7 +1756,7 @@ NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
void
NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
{
- if (new_maxpoll < MIN_POLL)
+ if (new_maxpoll < MIN_POLL || new_maxpoll > MAX_POLL)
return;
inst->maxpoll = new_maxpoll;
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new maxpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_maxpoll);
@@ -1883,13 +1890,37 @@ NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
}
}
- if (status == ADF_BADSUBNET) {
+ if (status != ADF_SUCCESS)
return 0;
- } else if (status == ADF_SUCCESS) {
- return 1;
+
+ /* Keep server sockets open only when an address allowed */
+ if (allow) {
+ NTP_Remote_Address remote_addr;
+
+ if (server_sock_fd4 == INVALID_SOCK_FD &&
+ ADF_IsAnyAllowed(access_auth_table, IPADDR_INET4)) {
+ remote_addr.ip_addr.family = IPADDR_INET4;
+ server_sock_fd4 = NIO_OpenServerSocket(&remote_addr);
+ }
+ if (server_sock_fd6 == INVALID_SOCK_FD &&
+ ADF_IsAnyAllowed(access_auth_table, IPADDR_INET6)) {
+ remote_addr.ip_addr.family = IPADDR_INET6;
+ server_sock_fd6 = NIO_OpenServerSocket(&remote_addr);
+ }
} else {
- return 0;
+ if (server_sock_fd4 != INVALID_SOCK_FD &&
+ !ADF_IsAnyAllowed(access_auth_table, IPADDR_INET4)) {
+ NIO_CloseServerSocket(server_sock_fd4);
+ server_sock_fd4 = INVALID_SOCK_FD;
+ }
+ if (server_sock_fd6 != INVALID_SOCK_FD &&
+ !ADF_IsAnyAllowed(access_auth_table, IPADDR_INET6)) {
+ NIO_CloseServerSocket(server_sock_fd6);
+ server_sock_fd6 = INVALID_SOCK_FD;
+ }
}
+
+ return 1;
}
/* ================================================== */
@@ -1941,3 +1972,46 @@ int NCR_IsSyncPeer(NCR_Instance inst)
}
/* ================================================== */
+
+static void
+broadcast_timeout(void *arg)
+{
+ BroadcastDestination *destination;
+ NTP_int64 orig_ts;
+ struct timeval recv_ts;
+
+ destination = ARR_GetElement(broadcasts, (long)arg);
+
+ orig_ts.hi = 0;
+ orig_ts.lo = 0;
+ recv_ts.tv_sec = 0;
+ recv_ts.tv_usec = 0;
+
+ transmit_packet(MODE_BROADCAST, 6 /* FIXME: should this be log2(interval)? */,
+ NTP_VERSION, 0, 0, &orig_ts, &recv_ts, NULL, NULL,
+ &destination->addr, &destination->local_addr);
+
+ /* Requeue timeout. We don't care if interval drifts gradually. */
+ SCH_AddTimeoutInClass(destination->interval, SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
+ SCH_NtpBroadcastClass, broadcast_timeout, arg);
+}
+
+/* ================================================== */
+
+void
+NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
+{
+ BroadcastDestination *destination;
+
+ destination = (BroadcastDestination *)ARR_GetNewElement(broadcasts);
+
+ destination->addr.ip_addr = *addr;
+ destination->addr.port = port;
+ destination->local_addr.ip_addr.family = IPADDR_UNSPEC;
+ destination->local_addr.sock_fd = NIO_OpenServerSocket(&destination->addr);
+ destination->interval = interval;
+
+ SCH_AddTimeoutInClass(destination->interval, SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
+ SCH_NtpBroadcastClass, broadcast_timeout,
+ (void *)(long)(ARR_GetSize(broadcasts) - 1));
+}
diff --git a/ntp_core.h b/ntp_core.h
index d9a5e32..db624e1 100644
--- a/ntp_core.h
+++ b/ntp_core.h
@@ -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 */
diff --git a/ntp_io.c b/ntp_io.c
index e0f7aea..571292a 100644
--- a/ntp_io.c
+++ b/ntp_io.c
@@ -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");
- }
+ 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_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 */
-
-int
-NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
-{
- return send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE, remote_addr, local_addr);
-}
-
-/* ================================================== */
-/* Send an authenticated packet to a given address */
+/* Send a packet to a given address */
int
-NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len)
+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 + auth_len, remote_addr, local_addr);
+ return send_packet((void *) packet, length, remote_addr, local_addr);
}
diff --git a/ntp_io.h b/ntp_io.h
index 99e0ade..cbdee56 100644
--- a/ntp_io.h
+++ b/ntp_io.h
@@ -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 */
diff --git a/ntp_sources.c b/ntp_sources.c
index c98053c..9c56255 100644
--- a/ntp_sources.c
+++ b/ntp_sources.c
@@ -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)
{
- struct UnresolvedSource *us, **i, *next;
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;
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 */
+static void
+append_unresolved_source(struct UnresolvedSource *us)
+{
+ 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_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params)
+NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params)
{
- struct UnresolvedSource *us, **i;
+ 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 = name;
+ us->name = Strdup(name);
us->port = port;
- us->type = type;
- us->params = *params;
- us->next = NULL;
+ us->replacement = 0;
+ us->new_source.type = type;
+ us->new_source.params = *params;
- for (i = &unresolved_sources; *i; i = &(*i)->next)
- ;
- *i = us;
+ 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,63 +616,149 @@ 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));
+ rehash_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;
+ return NSR_Success;
+}
- find_slot(temp_records[i].remote_addr, &slot, &found);
- assert(!found);
+/* ================================================== */
+
+void
+NSR_RemoveAllSources(void)
+{
+ SourceRecord *record;
+ unsigned int i;
- records[slot].remote_addr = temp_records[i].remote_addr;
- records[slot].data = temp_records[i].data;
+ for (i = 0; i < ARR_GetSize(records); i++) {
+ record = get_record(i);
+ if (!record->remote_addr)
+ continue;
+ clean_source_record(record);
}
- return NSR_Success;
+ 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_RemoveAllSources(void)
+NSR_HandleBadSource(IPAddr *address)
{
- int i;
+ static struct timeval last_replacement;
+ struct timeval now;
+ NTP_Remote_Address remote_addr;
+ SourceRecord *record;
+ int slot, found;
+ double diff;
- for (i = 0; i < N_RECORDS; i++) {
- if (!records[i].remote_addr)
- continue;
- NCR_DestroyInstance(records[i].data);
- records[i].remote_addr = NULL;
+ 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);
}
}
diff --git a/ntp_sources.h b/ntp_sources.h
index ee282ea..828a446 100644
--- a/ntp_sources.h
+++ b/ntp_sources.h
@@ -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);
diff --git a/pktlength.c b/pktlength.c
index 03a5a7e..be773c2 100644
--- a/pktlength.c
+++ b/pktlength.c
@@ -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);
}
diff --git a/refclock.c b/refclock.c
index 5c21f12..26193f6 100644
--- a/refclock.c
+++ b/refclock.c
@@ -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
diff --git a/refclock.h b/refclock.h
index b2122d3..08996a7 100644
--- a/refclock.h
+++ b/refclock.h
@@ -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;
diff --git a/refclock_pps.c b/refclock_pps.c
index b17f496..cd3cd83 100644
--- a/refclock_pps.c
+++ b/refclock_pps.c
@@ -29,7 +29,7 @@
#include "refclock.h"
-#if HAVE_PPSAPI
+#if FEAT_PPS
#if defined(HAVE_SYS_TIMEPPS_H)
#include <sys/timepps.h>
diff --git a/reference.c b/reference.c
index 4b231a7..4213a58 100644
--- a/reference.c
+++ b/reference.c
@@ -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)
{
@@ -1126,6 +1259,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)
{
enable_local_stratum = 1;
@@ -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;
diff --git a/reference.h b/reference.h
index fc91840..6ffc97d 100644
--- a/reference.h
+++ b/reference.h
@@ -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);
diff --git a/reports.h b/reports.h
index 5ea504f..1860e78 100644
--- a/reports.h
+++ b/reports.h
@@ -87,16 +87,6 @@ typedef struct {
} 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;
unsigned long peer_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 */
diff --git a/rtc.c b/rtc.c
index 46a6073..2d0f9cd 100644
--- a/rtc.c
+++ b/rtc.c
@@ -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);
}
}
diff --git a/rtc_linux.c b/rtc_linux.c
index 0b2b0d0..40befb3 100644
--- a/rtc_linux.c
+++ b/rtc_linux.c
@@ -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");
diff --git a/sched.c b/sched.c
index 7f3fd78..1946745 100644
--- a/sched.c
+++ b/sched.c
@@ -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;
diff --git a/smooth.c b/smooth.c
new file mode 100644
index 0000000..ae64ca3
--- /dev/null
+++ b/smooth.c
@@ -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;
+}
diff --git a/smooth.h b/smooth.h
new file mode 100644
index 0000000..72e67af
--- /dev/null
+++ b/smooth.h
@@ -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
diff --git a/sources.c b/sources.c
index 30a3abe..c6a67c5 100644
--- a/sources.c
+++ b/sources.c
@@ -36,6 +36,7 @@
#include "sourcestats.h"
#include "memory.h"
#include "ntp.h" /* For NTP_Leap */
+#include "ntp_sources.h"
#include "local.h"
#include "reference.h"
#include "util.h"
@@ -60,20 +61,27 @@ struct SelectInfo {
double root_distance;
double lo_limit;
double hi_limit;
+ double last_sample_ago;
};
/* ================================================== */
/* This enum contains the flag values that are used to label
each source */
typedef enum {
- SRC_OK, /* OK so far */
- SRC_UNREACHABLE, /* Source is not reachable */
- SRC_BAD_STATS, /* Stats driver could not supply valid
- data */
- SRC_FALSETICKER, /* Source is found to be a falseticker */
- SRC_JITTERY, /* Source scatter worse than other's dispersion */
- SRC_SELECTABLE, /* Source is acceptable candidate */
- SRC_SYNC /* Current synchronisation source */
+ SRC_OK, /* OK so far, not a final status! */
+ SRC_UNSELECTABLE, /* Has noselect option set */
+ SRC_BAD_STATS, /* Doesn't have valid stats data */
+ SRC_WAITS_STATS, /* Others have bad stats, selection postponed */
+ SRC_STALE, /* Has older samples than others */
+ SRC_FALSETICKER, /* Doesn't agree with others */
+ SRC_JITTERY, /* Scatter worse than other's dispersion (not used) */
+ SRC_WAITS_SOURCES, /* Not enough sources, selection postponed */
+ SRC_NONPREFERRED, /* Others have prefer option */
+ SRC_WAITS_UPDATE, /* No updates, selection postponed */
+ SRC_DISTANT, /* Others have shorter root distance */
+ SRC_OUTLIER, /* Outlier in clustering (not used yet) */
+ SRC_UNSELECTED, /* Used for synchronisation, not system peer */
+ SRC_SELECTED, /* Used for synchronisation, selected as system peer */
} SRC_Status;
/* ================================================== */
@@ -88,9 +96,6 @@ struct SRC_Instance_Record {
reference _it_ is sync'd to) */
IPAddr *ip_addr; /* Its IP address if NTP source */
- /* Flag indicating that we can use this source as a reference */
- int selectable;
-
/* Flag indicating that the source is updating reachability */
int active;
@@ -100,8 +105,11 @@ struct SRC_Instance_Record {
/* Number of set bits in the reachability register */
int reachability_size;
+ /* Updates since last reference update */
+ int updates;
+
/* Updates left before allowing combining */
- int outlier;
+ int distant;
/* Flag indicating the status of the source */
SRC_Status status;
@@ -123,7 +131,10 @@ struct SRC_Instance_Record {
struct Sort_Element {
int index;
double offset;
- enum {LOW=-1, CENTRE=0, HIGH=1} tag;
+ enum {
+ LOW = -1,
+ HIGH = 1
+ } tag;
};
/* ================================================== */
@@ -142,8 +153,8 @@ static int selected_source_index; /* Which source index is currently
/* Score needed to replace the currently selected source */
#define SCORE_LIMIT 10.0
-/* Number of updates needed to reset the outlier status */
-#define OUTLIER_PENALTY 32
+/* Number of updates needed to reset the distant status */
+#define DISTANT_PENALTY 32
static double reselect_distance;
static double stratum_weight;
@@ -165,6 +176,7 @@ source_to_string(SRC_Instance inst);
void SRC_Initialise(void) {
sources = NULL;
sort_list = NULL;
+ sel_sources = NULL;
n_sources = 0;
max_n_sources = 0;
selected_source_index = INVALID_SOURCE;
@@ -183,6 +195,11 @@ void SRC_Finalise(void)
{
LCL_RemoveParameterChangeHandler(slew_sources, NULL);
LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
+
+ Free(sources);
+ Free(sort_list);
+ Free(sel_sources);
+
initialised = 0;
}
@@ -190,18 +207,23 @@ void SRC_Finalise(void)
/* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */
-SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr)
+SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr, int min_samples, int max_samples)
{
SRC_Instance result;
assert(initialised);
+ if (min_samples == SRC_DEFAULT_MINSAMPLES)
+ min_samples = CNF_GetMinSamples();
+ if (max_samples == SRC_DEFAULT_MAXSAMPLES)
+ max_samples = CNF_GetMaxSamples();
+
result = MallocNew(struct SRC_Instance_Record);
- result->stats = SST_CreateInstance(ref_id, addr);
+ result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples);
if (n_sources == max_n_sources) {
/* Reallocate memory */
- max_n_sources += 32;
+ max_n_sources = max_n_sources > 0 ? 2 * max_n_sources : 4;
if (sources) {
sources = ReallocArray(struct SRC_Instance_Record *, max_n_sources, sources);
sort_list = ReallocArray(struct Sort_Element, 3*max_n_sources, sort_list);
@@ -214,20 +236,14 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOpt
}
sources[n_sources] = result;
+
result->index = n_sources;
- result->leap_status = LEAP_Normal;
- result->ref_id = ref_id;
- result->ip_addr = addr;
- result->active = 0;
- result->selectable = 0;
- result->reachability = 0;
- result->reachability_size = 0;
- result->outlier = 0;
- result->status = SRC_BAD_STATS;
result->type = type;
- result->sel_score = 1.0;
result->sel_option = sel_option;
+ SRC_SetRefid(result, ref_id, addr);
+ SRC_ResetInstance(result);
+
n_sources++;
return result;
@@ -245,8 +261,6 @@ void SRC_DestroyInstance(SRC_Instance instance)
assert(initialised);
- SRC_UnsetSelectable(instance);
-
SST_DeleteInstance(instance->stats);
dead_index = instance->index;
for (i=dead_index; i<n_sources-1; i++) {
@@ -256,9 +270,38 @@ void SRC_DestroyInstance(SRC_Instance instance)
--n_sources;
Free(instance);
- if (selected_source_index > dead_index) {
+ /* If this was the previous reference source, we have to reselect! */
+ if (selected_source_index == dead_index)
+ SRC_ReselectSource();
+ else if (selected_source_index > dead_index)
--selected_source_index;
- }
+}
+
+/* ================================================== */
+
+void
+SRC_ResetInstance(SRC_Instance instance)
+{
+ instance->leap_status = LEAP_Normal;
+ instance->active = 0;
+ instance->updates = 0;
+ instance->reachability = 0;
+ instance->reachability_size = 0;
+ instance->distant = 0;
+ instance->status = SRC_BAD_STATS;
+ instance->sel_score = 1.0;
+
+ SST_ResetInstance(instance->stats);
+}
+
+/* ================================================== */
+
+void
+SRC_SetRefid(SRC_Instance instance, uint32_t ref_id, IPAddr *addr)
+{
+ instance->ref_id = ref_id;
+ instance->ip_addr = addr;
+ SST_SetRefid(instance->stats, ref_id, addr);
}
/* ================================================== */
@@ -341,37 +384,6 @@ SRC_UnsetActive(SRC_Instance inst)
/* ================================================== */
-void
-SRC_SetSelectable(SRC_Instance inst)
-{
- inst->selectable = 1;
-
- DEBUG_LOG(LOGF_Sources, "%s", source_to_string(inst));
-
- /* Don't do selection at this point, though - that will come about
- in due course when we get some useful data from the source */
-}
-
-/* ================================================== */
-
-void
-SRC_UnsetSelectable(SRC_Instance inst)
-{
- inst->selectable = 0;
-
- DEBUG_LOG(LOGF_Sources, "%s%s", source_to_string(inst),
- (inst->index == selected_source_index) ? "(REF)":"");
-
- /* If this was the previous reference source, we have to reselect! */
-
- if (inst->index == selected_source_index) {
- SRC_SelectSource(NULL);
- }
-
-}
-
-/* ================================================== */
-
static int
special_mode_end(void)
{
@@ -414,6 +426,12 @@ SRC_UpdateReachability(SRC_Instance inst, int reachable)
if (REF_GetMode() != REF_ModeNormal && special_mode_end()) {
REF_SetUnsynchronised();
}
+
+ /* Try to replace NTP sources that are unreachable or falsetickers */
+ if (inst->type == SRC_NTP && (inst->status == SRC_FALSETICKER ||
+ (!inst->reachability && inst->reachability_size == SOURCE_REACH_BITS))) {
+ NSR_HandleBadSource(inst->ip_addr);
+ }
}
/* ================================================== */
@@ -421,13 +439,9 @@ SRC_UpdateReachability(SRC_Instance inst, int reachable)
void
SRC_ResetReachability(SRC_Instance inst)
{
- /* This should be disabled until source selection is modified to keep
- a peer selected even when not reachable */
-#if 0
inst->reachability = 0;
inst->reachability_size = 0;
SRC_UpdateReachability(inst, 0);
-#endif
}
/* ================================================== */
@@ -479,13 +493,27 @@ source_to_string(SRC_Instance inst)
/* ================================================== */
+static void
+mark_ok_sources(SRC_Status status)
+{
+ int i;
+
+ for (i = 0; i < n_sources; i++) {
+ if (sources[i]->status != SRC_OK)
+ continue;
+ sources[i]->status = status;
+ }
+}
+
+/* ================================================== */
+
static int
combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
double *offset_sd, double *frequency, double *skew)
{
struct timeval src_ref_time;
double src_offset, src_offset_sd, src_frequency, src_skew;
- double src_root_delay, src_root_dispersion, elapsed;
+ double src_root_delay, src_root_dispersion, sel_src_distance, elapsed;
double offset_weight, sum_offset_weight, sum_offset, sum2_offset_sd;
double frequency_weight, sum_frequency_weight, sum_frequency, inv_sum2_skew;
int i, index, combined;
@@ -496,6 +524,10 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
sum_offset_weight = sum_offset = sum2_offset_sd = 0.0;
sum_frequency_weight = sum_frequency = inv_sum2_skew = 0.0;
+ sel_src_distance = sources[selected_source_index]->sel_info.root_distance;
+ if (sources[selected_source_index]->type == SRC_NTP)
+ sel_src_distance += reselect_distance;
+
for (i = combined = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
SST_GetTrackingData(sources[index]->stats, &src_ref_time,
@@ -505,22 +537,26 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
/* Don't include this source if its distance is longer than the distance of
the selected source multiplied by the limit, their estimated frequencies
- are not close, or it was recently marked as outlier */
+ are not close, or it was recently marked as distant */
if (index != selected_source_index &&
- (sources[index]->sel_info.root_distance > combine_limit *
- (reselect_distance + sources[selected_source_index]->sel_info.root_distance) ||
+ (sources[index]->sel_info.root_distance > combine_limit * sel_src_distance ||
fabs(*frequency - src_frequency) >
combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) {
/* Use a smaller penalty in first few updates */
- sources[index]->outlier = sources[index]->reachability_size >= SOURCE_REACH_BITS ?
- OUTLIER_PENALTY : 1;
- } else if (sources[index]->outlier) {
- sources[index]->outlier--;
+ sources[index]->distant = sources[index]->reachability_size >= SOURCE_REACH_BITS ?
+ DISTANT_PENALTY : 1;
+ } else if (sources[index]->distant) {
+ sources[index]->distant--;
}
- if (sources[index]->outlier)
+ if (sources[index]->distant) {
+ sources[index]->status = SRC_DISTANT;
continue;
+ }
+
+ if (sources[index]->status == SRC_OK)
+ sources[index]->status = SRC_UNSELECTED;
UTI_DiffTimevalsToDouble(&elapsed, ref_time, &src_ref_time);
src_offset += elapsed * src_frequency;
@@ -556,39 +592,30 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
/* ================================================== */
/* This function selects the current reference from amongst the pool
- of sources we are holding.
-
- Updates are only made to the local reference if a new source is selected
- or match_refid is equal to the selected reference source refid */
+ of sources we are holding and updates the local reference */
void
SRC_SelectSource(SRC_Instance updated_inst)
{
- int i, j, index, old_selected_index, sel_prefer;
+ struct SelectInfo *si;
struct timeval now, ref_time;
+ int i, j, j1, j2, index, sel_prefer, n_endpoints, n_sel_sources;
+ int n_badstats_sources, max_sel_reach, max_badstat_reach;
+ int depth, best_depth, combined, stratum, min_stratum, max_score_index;
double src_offset, src_offset_sd, src_frequency, src_skew;
double src_root_delay, src_root_dispersion;
- int n_endpoints, j1, j2;
- double best_lo, best_hi;
- int depth, best_depth;
- int n_sel_sources, combined;
- double distance, sel_src_distance;
- int stratum, min_stratum;
- struct SelectInfo *si;
- int n_badstats_sources;
- int max_sel_reach, max_badstat_reach;
- int max_score_index;
- double max_score;
+ double best_lo, best_hi, distance, sel_src_distance, max_score;
+ double first_sample_ago, max_reach_sample_ago;
+ NTP_Leap leap_status;
- NTP_Leap leap_status = LEAP_Normal;
- old_selected_index = selected_source_index;
+ if (updated_inst)
+ updated_inst->updates++;
if (n_sources == 0) {
/* In this case, we clearly cannot synchronise to anything */
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no sources", NULL);
selected_source_index = INVALID_SOURCE;
- REF_SetUnsynchronised();
}
return;
}
@@ -597,395 +624,364 @@ SRC_SelectSource(SRC_Instance updated_inst)
SCH_GetLastEventTime(&now, NULL, NULL);
/* Step 1 - build intervals about each source */
+
n_endpoints = 0;
n_sel_sources = 0;
n_badstats_sources = 0;
max_sel_reach = max_badstat_reach = 0;
- for (i=0; i<n_sources; i++) {
-
- if (sources[i]->selectable && sources[i]->reachability &&
- sources[i]->sel_option != SRC_SelectNoselect) {
+ max_reach_sample_ago = 0.0;
- si = &(sources[i]->sel_info);
- SST_GetSelectionData(sources[i]->stats, &now,
- &(si->stratum),
- &(si->lo_limit),
- &(si->hi_limit),
- &(si->root_distance),
- &(si->variance),
- &(si->select_ok));
+ for (i = 0; i < n_sources; i++) {
+ assert(sources[i]->status != SRC_OK);
- if (si->select_ok) {
- ++n_sel_sources;
+ /* Ignore sources which were added with the noselect option */
+ if (sources[i]->sel_option == SRC_SelectNoselect) {
+ sources[i]->status = SRC_UNSELECTABLE;
+ continue;
+ }
- sources[i]->status = SRC_OK; /* For now */
+ si = &sources[i]->sel_info;
+ SST_GetSelectionData(sources[i]->stats, &now, &si->stratum,
+ &si->lo_limit, &si->hi_limit, &si->root_distance,
+ &si->variance, &first_sample_ago,
+ &si->last_sample_ago, &si->select_ok);
+
+ if (!si->select_ok) {
+ ++n_badstats_sources;
+ sources[i]->status = SRC_BAD_STATS;
+ if (max_badstat_reach < sources[i]->reachability)
+ max_badstat_reach = sources[i]->reachability;
+ continue;
+ }
- /* Otherwise it will be hard to pick this one later! However,
- this test might be too strict, we might want to dump it */
- j1 = n_endpoints;
- j2 = j1 + 1;
+ sources[i]->status = SRC_OK; /* For now */
- sort_list[j1].index = i;
- sort_list[j1].offset = si->lo_limit;
- sort_list[j1].tag = LOW;
+ if (sources[i]->reachability && max_reach_sample_ago < first_sample_ago)
+ max_reach_sample_ago = first_sample_ago;
- sort_list[j2].index = i;
- sort_list[j2].offset = si->hi_limit;
- sort_list[j2].tag = HIGH;
+ if (max_sel_reach < sources[i]->reachability)
+ max_sel_reach = sources[i]->reachability;
+ }
- n_endpoints += 2;
+ for (i = 0; i < n_sources; i++) {
+ if (sources[i]->status != SRC_OK)
+ continue;
- if (max_sel_reach < sources[i]->reachability) {
- max_sel_reach = sources[i]->reachability;
- }
- } else {
- ++n_badstats_sources;
- sources[i]->status = SRC_BAD_STATS;
+ si = &sources[i]->sel_info;
- if (max_badstat_reach < sources[i]->reachability) {
- max_badstat_reach = sources[i]->reachability;
- }
- }
- } else {
- /* If the source is not reachable, there is no way we will pick
- it. */
- sources[i]->status = SRC_UNREACHABLE;
+ /* Reachability is not a requirement for selection. An unreachable source
+ can still be selected if its newest sample is not older than the oldest
+ sample from reachable sources. */
+ if (!sources[i]->reachability && max_reach_sample_ago < si->last_sample_ago) {
+ sources[i]->status = SRC_STALE;
+ continue;
}
+
+ ++n_sel_sources;
+
+ j1 = n_endpoints;
+ j2 = j1 + 1;
+
+ sort_list[j1].index = i;
+ sort_list[j1].offset = si->lo_limit;
+ sort_list[j1].tag = LOW;
+
+ sort_list[j2].index = i;
+ sort_list[j2].offset = si->hi_limit;
+ sort_list[j2].tag = HIGH;
+
+ n_endpoints += 2;
}
- DEBUG_LOG(LOGF_Sources, "badstat_sources=%d sel_sources=%d badstat_reach=%x sel_reach=%x",
- n_badstats_sources, n_sel_sources, max_badstat_reach, max_sel_reach);
+ DEBUG_LOG(LOGF_Sources, "badstat=%d sel=%d badstat_reach=%x sel_reach=%x max_reach_ago=%f",
+ n_badstats_sources, n_sel_sources, max_badstat_reach,
+ max_sel_reach, max_reach_sample_ago);
/* Wait for the next call if we have no source selected and there is
a source with bad stats (has less than 3 samples) with reachability
equal to shifted maximum reachability of sources with valid stats.
This delays selecting source on start with servers using the same
polling interval until they all have valid stats. */
-
if (n_badstats_sources && n_sel_sources &&
- selected_source_index == INVALID_SOURCE &&
+ selected_source_index == INVALID_SOURCE &&
max_sel_reach >> 1 == max_badstat_reach) {
+ mark_ok_sources(SRC_WAITS_STATS);
+ return;
+ }
+
+ if (n_endpoints == 0) {
+ /* No sources provided valid endpoints */
+ if (selected_source_index != INVALID_SOURCE) {
+ log_selection_message("Can't synchronise: no selectable sources", NULL);
+ selected_source_index = INVALID_SOURCE;
+ }
return;
}
/* Now sort the endpoint list */
- if (n_endpoints > 0) {
-
- /* Sort the list into order */
- qsort((void *) sort_list, n_endpoints, sizeof(struct Sort_Element), compare_sort_elements);
-
- /* Now search for the interval which is contained in the most
- individual source intervals. Any source which overlaps this
- will be a candidate.
-
- If we get a case like
-
- <----------------------->
- <-->
- <-->
- <===========>
-
- we will build the interval as shown with '=', whereas with an extra source we get
- <----------------------->
- <------->
- <-->
- <-->
- <==>
-
- The first case is just bad luck - we need extra sources to
- detect the falseticker, so just make an arbitrary choice based
- on stratum & stability etc.
- */
-
- depth = best_depth = 0;
- best_lo = best_hi = 0.0;
-
- for (i=0; i<n_endpoints; i++) {
- switch(sort_list[i].tag) {
- case LOW:
- depth++;
- if (depth > best_depth) {
- best_depth = depth;
- best_lo = sort_list[i].offset;
- }
- break;
-
- case CENTRE:
- assert(0);
- break;
-
- case HIGH:
- if (depth == best_depth) {
- best_hi = sort_list[i].offset;
- }
- depth--;
- break;
+ qsort((void *) sort_list, n_endpoints, sizeof(struct Sort_Element), compare_sort_elements);
+
+ /* Now search for the interval which is contained in the most
+ individual source intervals. Any source which overlaps this
+ will be a candidate.
+
+ If we get a case like
+
+ <----------------------->
+ <-->
+ <-->
+ <===========>
+
+ we will build the interval as shown with '=', whereas with an extra source we get
+ <----------------------->
+ <------->
+ <-->
+ <-->
+ <==>
+
+ The first case is just bad luck - we need extra sources to
+ detect the falseticker, so just make an arbitrary choice based
+ on stratum & stability etc.
+ */
+
+ depth = best_depth = 0;
+ best_lo = best_hi = 0.0;
+
+ for (i = 0; i < n_endpoints; i++) {
+ switch (sort_list[i].tag) {
+ case LOW:
+ depth++;
+ if (depth > best_depth) {
+ best_depth = depth;
+ best_lo = sort_list[i].offset;
+ }
+ break;
+ case HIGH:
+ if (depth == best_depth)
+ best_hi = sort_list[i].offset;
+ depth--;
+ break;
+ default:
+ assert(0);
+ }
+ }
- }
+ if (best_depth <= n_sel_sources / 2) {
+ /* Could not even get half the reachable sources to agree -
+ clearly we can't synchronise. */
+
+ if (selected_source_index != INVALID_SOURCE) {
+ log_selection_message("Can't synchronise: no majority", NULL);
+ REF_SetUnsynchronised();
+ selected_source_index = INVALID_SOURCE;
}
- if (best_depth <= n_sel_sources/2) {
- /* Could not even get half the reachable sources to agree -
- clearly we can't synchronise.
+ /* .. and mark all sources as falsetickers (so they appear thus
+ on the outputs from the command client) */
+ mark_ok_sources(SRC_FALSETICKER);
- srcs #to agree
- 1 1
- 2 2
- 3 2
- 4 3 etc
+ return;
+ }
- */
+ /* We have our interval, now work out which source are in it,
+ i.e. build list of admissible sources. */
- if (selected_source_index != INVALID_SOURCE) {
- log_selection_message("Can't synchronise: no majority", NULL);
- }
- selected_source_index = INVALID_SOURCE;
+ n_sel_sources = 0;
- /* .. and mark all sources as falsetickers (so they appear thus
- on the outputs from the command client) */
+ for (i = 0; i < n_sources; i++) {
+ if (sources[i]->status != SRC_OK)
+ continue;
- for (i=0; i<n_sources; i++) {
- sources[i]->status = SRC_FALSETICKER;
- }
+ /* This should be the same condition to get into the endpoint
+ list */
+ /* Check if source's interval contains the best interval, or
+ is wholly contained within it */
+ if ((sources[i]->sel_info.lo_limit <= best_lo &&
+ sources[i]->sel_info.hi_limit >= best_hi) ||
+ (sources[i]->sel_info.lo_limit >= best_lo &&
+ sources[i]->sel_info.hi_limit <= best_hi)) {
+ sel_sources[n_sel_sources++] = i;
} else {
-
- /* We have our interval, now work out which source are in it,
- i.e. build list of admissible sources. */
-
- n_sel_sources = 0;
- for (i=0; i<n_sources; i++) {
- if (sources[i]->status == SRC_OK) {
- /* This should be the same condition to get into the endpoint
- list */
- /* Check if source's interval contains the best interval, or
- is wholly contained within it */
- if (((sources[i]->sel_info.lo_limit <= best_lo) &&
- (sources[i]->sel_info.hi_limit >= best_hi)) ||
- ((sources[i]->sel_info.lo_limit >= best_lo) &&
- (sources[i]->sel_info.hi_limit <= best_hi))) {
-
- sel_sources[n_sel_sources++] = i;
- } else {
- sources[i]->status = SRC_FALSETICKER;
- }
- }
- }
+ sources[i]->status = SRC_FALSETICKER;
+ }
+ }
-#if 0
- /* We now have a list of indices for the sources which pass the
- false-ticker test. Now go on to reject those whose variance is
- greater than the minimum distance of any other */
-
- /* Find minimum distance */
- index = sel_sources[0];
- min_distance = sources[index]->sel_info.root_distance;
- for (i=1; i<n_sel_sources; i++) {
- index = sel_sources[i];
- distance = sources[index]->sel_info.root_distance;
- if (distance < min_distance) {
- min_distance = distance;
- }
- }
+ if (n_sel_sources == 0 || n_sel_sources < CNF_GetMinSources()) {
+ if (selected_source_index != INVALID_SOURCE) {
+ log_selection_message("Can't synchronise: %s selectable sources",
+ n_sel_sources ? "not enough" : "no");
+ selected_source_index = INVALID_SOURCE;
+ }
+ mark_ok_sources(SRC_WAITS_SOURCES);
+ return;
+ }
- /* Now go through and prune any NTP sources that have excessive
- variance */
- for (i=0; i<n_sel_sources; i++) {
- index = sel_sources[i];
- if (sources[index]->type == SRC_NTP &&
- sqrt(sources[index]->sel_info.variance) > min_distance) {
- sel_sources[i] = INVALID_SOURCE;
- sources[index]->status = SRC_JITTERY;
- }
- }
-#endif
-
- /* Now crunch the list and mark all sources as selectable */
- for (i=j=0; i<n_sel_sources; i++) {
- index = sel_sources[i];
- if (index != INVALID_SOURCE) {
- sources[index]->status = SRC_SELECTABLE;
- sel_sources[j++] = sel_sources[i];
- }
- }
- n_sel_sources = j;
-
- if (n_sel_sources > 0) {
- /* Accept leap second status if more than half of selectable sources agree */
-
- for (i=j1=j2=0; i<n_sel_sources; i++) {
- index = sel_sources[i];
- if (sources[index]->leap_status == LEAP_InsertSecond) {
- j1++;
- } else if (sources[index]->leap_status == LEAP_DeleteSecond) {
- j2++;
- }
- }
+ /* Accept leap second status if more than half of selectable sources agree */
+ for (i = j1 = j2 = 0; i < n_sel_sources; i++) {
+ index = sel_sources[i];
+ if (sources[index]->leap_status == LEAP_InsertSecond)
+ j1++;
+ else if (sources[index]->leap_status == LEAP_DeleteSecond)
+ j2++;
+ }
- if (j1 > n_sel_sources / 2) {
- leap_status = LEAP_InsertSecond;
- } else if (j2 > n_sel_sources / 2) {
- leap_status = LEAP_DeleteSecond;
- }
+ if (j1 > n_sel_sources / 2)
+ leap_status = LEAP_InsertSecond;
+ else if (j2 > n_sel_sources / 2)
+ leap_status = LEAP_DeleteSecond;
+ else
+ leap_status = LEAP_Normal;
+
+ /* If there are any sources with prefer option, reduce the list again
+ only to the preferred sources */
+ for (i = 0; i < n_sel_sources; i++) {
+ if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer)
+ break;
+ }
+ if (i < n_sel_sources) {
+ for (i = j = 0; i < n_sel_sources; i++) {
+ if (sources[sel_sources[i]]->sel_option != SRC_SelectPrefer)
+ sources[sel_sources[i]]->status = SRC_NONPREFERRED;
+ else
+ sel_sources[j++] = sel_sources[i];
+ }
+ assert(j > 0);
+ n_sel_sources = j;
+ sel_prefer = 1;
+ } else {
+ sel_prefer = 0;
+ }
- /* If there are any sources with prefer option, reduce the list again
- only to the prefer sources */
- for (i=j=0; i<n_sel_sources; i++) {
- if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer) {
- sel_sources[j++] = sel_sources[i];
- }
- }
- if (j > 0) {
- n_sel_sources = j;
- sel_prefer = 1;
- } else {
- sel_prefer = 0;
- }
+ /* Find minimum stratum */
- /* Now find minimum stratum. If none are left now,
- tough. RFC1305 is not so harsh on pruning sources due to
- excess variance, which prevents this from happening */
+ index = sel_sources[0];
+ min_stratum = sources[index]->sel_info.stratum;
+ for (i = 1; i < n_sel_sources; i++) {
+ index = sel_sources[i];
+ stratum = sources[index]->sel_info.stratum;
+ if (stratum < min_stratum)
+ min_stratum = stratum;
+ }
- index = sel_sources[0];
- min_stratum = sources[index]->sel_info.stratum;
- for (i=1; i<n_sel_sources; i++) {
- index = sel_sources[i];
- stratum = sources[index]->sel_info.stratum;
- if (stratum < min_stratum) min_stratum = stratum;
- }
+ /* Update scores and find the source with maximum score */
- /* Update scores and find source with maximum score */
+ max_score_index = INVALID_SOURCE;
+ max_score = 0.0;
+ sel_src_distance = 0.0;
- max_score_index = INVALID_SOURCE;
- max_score = 0.0;
- sel_src_distance = 0.0;
+ if (selected_source_index != INVALID_SOURCE)
+ sel_src_distance = sources[selected_source_index]->sel_info.root_distance +
+ (sources[selected_source_index]->sel_info.stratum - min_stratum) * stratum_weight;
- if (selected_source_index != INVALID_SOURCE) {
- sel_src_distance = sources[selected_source_index]->sel_info.root_distance +
- (sources[selected_source_index]->sel_info.stratum - min_stratum) * stratum_weight;
- }
+ for (i = 0; i < n_sources; i++) {
+ /* Reset score for non-selectable sources */
+ if (sources[i]->status != SRC_OK ||
+ (sel_prefer && sources[i]->sel_option != SRC_SelectPrefer)) {
+ sources[i]->sel_score = 1.0;
+ sources[i]->distant = DISTANT_PENALTY;
+ continue;
+ }
- for (i = 0; i < n_sources; i++) {
+ distance = sources[i]->sel_info.root_distance +
+ (sources[i]->sel_info.stratum - min_stratum) * stratum_weight;
+ if (sources[i]->type == SRC_NTP)
+ distance += reselect_distance;
- /* Reset score for non-selectable sources */
- if (sources[i]->status != SRC_SELECTABLE ||
- (sel_prefer && sources[i]->sel_option != SRC_SelectPrefer)) {
- sources[i]->sel_score = 1.0;
- sources[i]->outlier = OUTLIER_PENALTY;
- continue;
- }
-
- distance = sources[i]->sel_info.root_distance +
- (sources[i]->sel_info.stratum - min_stratum) * stratum_weight;
- if (sources[i]->type == SRC_NTP)
- distance += reselect_distance;
+ if (selected_source_index != INVALID_SOURCE) {
+ /* Update score, but only for source pairs where one source
+ has a new sample */
+ if (sources[i] == updated_inst ||
+ sources[selected_source_index] == updated_inst) {
- if (selected_source_index != INVALID_SOURCE) {
+ sources[i]->sel_score *= sel_src_distance / distance;
- /* Update score, but only for source pairs where one source
- has a new sample */
- if (sources[i] == updated_inst ||
- sources[selected_source_index] == updated_inst) {
+ if (sources[i]->sel_score < 1.0)
+ sources[i]->sel_score = 1.0;
+ }
+ } else {
+ /* When there is no selected source yet, assign scores so that the
+ source with minimum distance will have maximum score. The scores
+ will be reset when the source is selected later in this function. */
+ sources[i]->sel_score = 1.0 / distance;
+ }
- sources[i]->sel_score *= sel_src_distance / distance;
+ DEBUG_LOG(LOGF_Sources, "select score=%f refid=%"PRIx32" match_refid=%"PRIx32" status=%d dist=%f",
+ sources[i]->sel_score, sources[i]->ref_id,
+ updated_inst ? updated_inst->ref_id : 0,
+ sources[i]->status, distance);
- if (sources[i]->sel_score < 1.0)
- sources[i]->sel_score = 1.0;
- }
+ if (max_score < sources[i]->sel_score) {
+ max_score = sources[i]->sel_score;
+ max_score_index = i;
+ }
+ }
- } else {
+ assert(max_score_index != INVALID_SOURCE);
- /* When there is no selected source yet, assign scores so the
- source with minimum distance will have maximum score. The scores
- will be immediately reset. */
+ /* Is the current source still a survivor and no other source has reached
+ the score limit? */
+ if (selected_source_index == INVALID_SOURCE ||
+ sources[selected_source_index]->status != SRC_OK ||
+ (max_score_index != selected_source_index && max_score > SCORE_LIMIT)) {
- sources[i]->sel_score = 1.0 / distance;
- }
+ /* Before selecting the new synchronisation source wait until the reference
+ can be updated */
+ if (sources[max_score_index]->updates == 0) {
+ selected_source_index = INVALID_SOURCE;
+ mark_ok_sources(SRC_WAITS_UPDATE);
+ DEBUG_LOG(LOGF_Sources, "best source has no updates");
+ return;
+ }
- DEBUG_LOG(LOGF_Sources, "select score=%f refid=%x match_refid=%x status=%d dist=%f",
- sources[i]->sel_score, sources[i]->ref_id, updated_inst ? updated_inst->ref_id : 0,
- sources[i]->status, distance);
-
- if (max_score < sources[i]->sel_score) {
- max_score = sources[i]->sel_score;
- max_score_index = i;
- }
- }
+ selected_source_index = max_score_index;
+ log_selection_message("Selected source %s",
+ source_to_string(sources[selected_source_index]));
- assert(max_score_index != INVALID_SOURCE);
-
- /* Is the current source still a survivor
- and no other source has reached the score limit? */
-
- if ((selected_source_index == INVALID_SOURCE) ||
- (sources[selected_source_index]->status != SRC_SELECTABLE) ||
- (max_score_index != selected_source_index && max_score > SCORE_LIMIT)) {
-
- /* We have to elect a new synchronisation source */
-
- selected_source_index = max_score_index;
- log_selection_message("Selected source %s",
- source_to_string(sources[selected_source_index]));
-
- /* New source has been selected, reset all scores */
- for (i=0; i < n_sources; i++) {
- sources[i]->sel_score = 1.0;
- sources[i]->outlier = 0;
- }
- }
+ /* New source has been selected, reset all scores */
+ for (i = 0; i < n_sources; i++) {
+ sources[i]->sel_score = 1.0;
+ sources[i]->distant = 0;
+ }
+ }
- sources[selected_source_index]->status = SRC_SYNC;
-
- /* Update local reference only when a new source was selected
- or the selected source has a new sample */
- if (selected_source_index != old_selected_index ||
- updated_inst == sources[selected_source_index]) {
-
- /* Now just use the statistics of the selected source combined with
- the other selectable sources for trimming the local clock */
-
- SST_GetTrackingData(sources[selected_source_index]->stats, &ref_time,
- &src_offset, &src_offset_sd,
- &src_frequency, &src_skew,
- &src_root_delay, &src_root_dispersion);
-
- combined = combine_sources(n_sel_sources, &ref_time, &src_offset,
- &src_offset_sd, &src_frequency, &src_skew);
-
- REF_SetReference(sources[selected_source_index]->sel_info.stratum,
- leap_status,
- combined,
- sources[selected_source_index]->ref_id,
- sources[selected_source_index]->ip_addr,
- &ref_time,
- src_offset,
- src_offset_sd,
- src_frequency,
- src_skew,
- src_root_delay,
- src_root_dispersion);
- }
+ sources[selected_source_index]->status = SRC_SELECTED;
- } else {
- if (selected_source_index != INVALID_SOURCE) {
- log_selection_message("Can't synchronise: no selectable sources", NULL);
- }
- selected_source_index = INVALID_SOURCE;
- }
- }
+ /* Don't update reference when the selected source has no new samples */
- } else {
- /* No sources provided valid endpoints */
- if (selected_source_index != INVALID_SOURCE) {
- log_selection_message("Can't synchronise: no reachable sources", NULL);
+ if (sources[selected_source_index]->updates == 0) {
+ /* Mark the remaining sources as last combine_sources() call */
+
+ for (i = 0; i < n_sel_sources; i++) {
+ index = sel_sources[i];
+ if (sources[index]->status == SRC_OK)
+ sources[index]->status = sources[index]->distant ?
+ SRC_DISTANT : SRC_UNSELECTED;
}
- selected_source_index = INVALID_SOURCE;
+ return;
}
- if (selected_source_index == INVALID_SOURCE &&
- selected_source_index != old_selected_index) {
- REF_SetUnsynchronised();
- }
+ for (i = 0; i < n_sources; i++)
+ sources[i]->updates = 0;
+
+ /* Now just use the statistics of the selected source combined with
+ the other selectable sources for trimming the local clock */
+
+ SST_GetTrackingData(sources[selected_source_index]->stats, &ref_time,
+ &src_offset, &src_offset_sd,
+ &src_frequency, &src_skew,
+ &src_root_delay, &src_root_dispersion);
+
+ combined = combine_sources(n_sel_sources, &ref_time, &src_offset,
+ &src_offset_sd, &src_frequency, &src_skew);
+
+ REF_SetReference(sources[selected_source_index]->sel_info.stratum,
+ leap_status, combined,
+ sources[selected_source_index]->ref_id,
+ sources[selected_source_index]->ip_addr,
+ &ref_time, src_offset, src_offset_sd,
+ src_frequency, src_skew,
+ src_root_delay, src_root_dispersion);
}
/* ================================================== */
@@ -1221,23 +1217,32 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
}
switch (src->status) {
- case SRC_SYNC:
- report->state = RPT_SYNC;
- break;
- case SRC_JITTERY:
- report->state = RPT_JITTERY;
- break;
- case SRC_OK:
+ case SRC_UNSELECTABLE:
case SRC_BAD_STATS:
- case SRC_UNREACHABLE:
+ case SRC_STALE:
+ case SRC_WAITS_STATS:
report->state = RPT_UNREACH;
break;
case SRC_FALSETICKER:
report->state = RPT_FALSETICKER;
break;
- case SRC_SELECTABLE:
- report->state = src->outlier ? RPT_OUTLIER : RPT_CANDIDATE;
+ case SRC_JITTERY:
+ report->state = RPT_JITTERY;
+ break;
+ case SRC_WAITS_SOURCES:
+ case SRC_NONPREFERRED:
+ case SRC_WAITS_UPDATE:
+ case SRC_DISTANT:
+ case SRC_OUTLIER:
+ report->state = RPT_OUTLIER;
+ break;
+ case SRC_UNSELECTED:
+ report->state = RPT_CANDIDATE;
break;
+ case SRC_SELECTED:
+ report->state = RPT_SYNC;
+ break;
+ case SRC_OK:
default:
assert(0);
break;
@@ -1245,7 +1250,7 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
switch (src->sel_option) {
case SRC_SelectNormal:
- report->sel_option = RPT_NOSELECT;
+ report->sel_option = RPT_NORMAL;
break;
case SRC_SelectPrefer:
report->sel_option = RPT_PREFER;
@@ -1300,27 +1305,6 @@ SRC_GetType(int index)
/* ================================================== */
-SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst)
-{
- SRC_Skew_Direction result = SRC_Skew_Nochange;
-
- switch (SST_LastSkewChange(inst->stats)) {
- case SST_Skew_Decrease:
- result = SRC_Skew_Decrease;
- break;
- case SST_Skew_Nochange:
- result = SRC_Skew_Nochange;
- break;
- case SST_Skew_Increase:
- result = SRC_Skew_Increase;
- break;
- }
-
- return result;
-}
-
-/* ================================================== */
-
int
SRC_Samples(SRC_Instance inst)
{
diff --git a/sources.h b/sources.h
index c28102c..8c6027b 100644
--- a/sources.h
+++ b/sources.h
@@ -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 */
diff --git a/sourcestats.c b/sourcestats.c
index 7259bde..52e5034 100644
--- a/sourcestats.c
+++ b/sourcestats.c
@@ -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;
@@ -226,6 +221,15 @@ SST_ResetInstance(SST_Stats inst)
}
/* ================================================== */
+
+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
diff --git a/sourcestats.h b/sourcestats.h
index 33005c9..cba0a65 100644
--- a/sourcestats.h
+++ b/sourcestats.h
@@ -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 */
diff --git a/srcparams.h b/srcparams.h
index 4e01d3b..826b78d 100644
--- a/srcparams.h
+++ b/srcparams.h
@@ -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 */
diff --git a/stubs.c b/stubs.c
new file mode 100644
index 0000000..01d85e3
--- /dev/null
+++ b/stubs.c
@@ -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 */
diff --git a/sys.c b/sys.c
index 765af09..f0c81df 100644
--- a/sys.c
+++ b/sys.c
@@ -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");
diff --git a/sys_generic.c b/sys_generic.c
index 2adbbfe..db343e5 100644
--- a/sys_generic.c
+++ b/sys_generic.c
@@ -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;
@@ -107,6 +108,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 */
static void
@@ -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));
}
/* ================================================== */
diff --git a/sys_generic.h b/sys_generic.h
index 45c14e2..4532083 100644
--- a/sys_generic.h
+++ b/sys_generic.h
@@ -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);
diff --git a/sys_linux.c b/sys_linux.c
index a8af8df..e5ca9a6 100644
--- a/sys_linux.c
+++ b/sys_linux.c
@@ -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) {
- return 0;
- }
-
- if (*hz == 100) {
- *shift_hz = 7;
- return 1;
- }
+ int hz;
- for (*shift_hz = 1; (*hz >> *shift_hz) > 1; (*shift_hz)++)
- ;
+ if ((hz = sysconf(_SC_CLK_TCK)) < 1)
+ return 0;
- 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");
}
diff --git a/sys_macosx.c b/sys_macosx.c
new file mode 100644
index 0000000..30945a4
--- /dev/null
+++ b/sys_macosx.c
@@ -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
diff --git a/broadcast.h b/sys_macosx.h
index 08ba6db..b579415 100644
--- a/broadcast.h
+++ b/sys_macosx.h
@@ -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
+ */
-#include "addressing.h"
+#ifndef GOT_SYS_MACOSX_H
+#define GOT_SYS_MACOSX_H
-extern void BRD_Initialise(void);
-extern void BRD_Finalise(void);
-extern void BRD_AddDestination(IPAddr *addr, unsigned short port, int interval);
+void SYS_MacOSX_Initialise(void);
-#endif /* GOT_BROADCAST_H */
+void SYS_MacOSX_Finalise(void);
+#endif
diff --git a/sys_netbsd.c b/sys_netbsd.c
index 8c08d4e..237f35f 100644
--- a/sys_netbsd.c
+++ b/sys_netbsd.c
@@ -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 */);
}
diff --git a/sys_solaris.c b/sys_solaris.c
index 0c8dedb..fe8b63a 100644
--- a/sys_solaris.c
+++ b/sys_solaris.c
@@ -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 */
diff --git a/sys_sunos.c b/sys_sunos.c
index d45f58f..7d0737e 100644
--- a/sys_sunos.c
+++ b/sys_sunos.c
@@ -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 */
diff --git a/sysincl.h b/sysincl.h
index 2ecccb7..5c1fb37 100644
--- a/sysincl.h
+++ b/sysincl.h
@@ -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
diff --git a/tempcomp.c b/tempcomp.c
index 2465bda..07cbbb9 100644
--- a/tempcomp.c
+++ b/tempcomp.c
@@ -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);
}
diff --git a/test/compilation/001-features b/test/compilation/001-features
new file mode 100755
index 0000000..b1f1fb6
--- /dev/null
+++ b/test/compilation/001-features
@@ -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
diff --git a/test/simulation/009-sourceselection b/test/simulation/009-sourceselection
new file mode 100755
index 0000000..a6c9759
--- /dev/null
+++ b/test/simulation/009-sourceselection
@@ -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
diff --git a/test/simulation/111-knownclient b/test/simulation/111-knownclient
index 13374ac..70ba2b1 100755
--- a/test/simulation/111-knownclient
+++ b/test/simulation/111-knownclient
@@ -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"
diff --git a/test/simulation/113-leapsecond b/test/simulation/113-leapsecond
index 3889d2e..7d67007 100755
--- a/test/simulation/113-leapsecond
+++ b/test/simulation/113-leapsecond
@@ -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
diff --git a/test/simulation/114-presend b/test/simulation/114-presend
index ddbac93..e9fe66e 100755
--- a/test/simulation/114-presend
+++ b/test/simulation/114-presend
@@ -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
diff --git a/test/simulation/116-minsources b/test/simulation/116-minsources
new file mode 100755
index 0000000..f32596a
--- /dev/null
+++ b/test/simulation/116-minsources
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+. test.common
+
+test_start "minsources directive"
+
+client_conf="minsources 3"
+
+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
+
+servers=3
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_packet_interval || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/test/simulation/117-fallbackdrift b/test/simulation/117-fallbackdrift
new file mode 100755
index 0000000..a4f3d0f
--- /dev/null
+++ b/test/simulation/117-fallbackdrift
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+. test.common
+test_start "fallback drift"
+
+limit=100000
+wander=0.0
+jitter=1e-6
+time_offset=10
+freq_offset="(* 1e-4 (sine 1000))"
+base_delay="(* -1.0 (equal 0.1 (min time 4250) 4250))"
+client_server_options="minpoll 4 maxpoll 4"
+client_conf="fallbackdrift 6 10"
+time_max_limit=1e0
+time_rms_limit=1e0
+freq_max_limit=5e-4
+freq_rms_limit=5e-4
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/test/simulation/118-maxdelay b/test/simulation/118-maxdelay
new file mode 100755
index 0000000..0e27847
--- /dev/null
+++ b/test/simulation/118-maxdelay
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+. test.common
+test_start "maxdelay options"
+
+max_sync_time=2000
+base_delay=1e-5
+jitter=1e-5
+wander=0.0
+freq_offset="(sum 1e-10)"
+time_rms_limit=2e-4
+
+client_server_options="maxdelay 3e-5 maxdelayratio 2.0 maxdelaydevratio 2.0"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+for client_server_options in "maxdelay 2e-5" \ "maxdelayratio 1.001"; do
+ run_test || test_fail
+ check_chronyd_exit || test_fail
+ check_packet_interval || test_fail
+ check_sync && test_fail
+done
+
+test_pass
diff --git a/test/simulation/119-smoothtime b/test/simulation/119-smoothtime
new file mode 100755
index 0000000..5b043e2
--- /dev/null
+++ b/test/simulation/119-smoothtime
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+. test.common
+test_start "smoothtime option"
+
+server_strata=2
+server_conf="smoothtime 400 0.001"
+min_sync_time=250
+max_sync_time=1000
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+limit=10000
+refclock_jitter=1e-4
+refclock_offset="(* 10.0 (equal 0.1 (max (sum 1.0) 1000) 1000))"
+server_step="(* -10.0 (equal 0.1 (sum 1.0) 1))"
+server_strata=1
+server_conf="refclock SHM 0 dpoll 4 poll 6
+smoothtime 2000 1"
+time_offset=-10
+client_server_options="minpoll 6 maxpoll 6"
+client_conf="corrtimeratio 100"
+min_sync_time=8000
+max_sync_time=8500
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+min_sync_time=$default_min_sync_time
+max_sync_time=$default_max_sync_time
+time_max_limit=11
+time_rms_limit=11
+freq_max_limit=1e-2
+freq_rms_limit=2e-3
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+refclock_jitter=1e-9
+refclock_offset="(* 1e-1 (triangle 1000) (+ -1.0 (pulse 1000 10000)))"
+server_step=""
+server_conf="refclock SHM 0 dpoll 4 poll 6 minsamples 4 maxsamples 4
+smoothtime 1e4 1e-6"
+client_server_options="minpoll 4 maxpoll 4"
+time_offset=0.1
+jitter=1e-6
+wander=0.0
+min_sync_time=30
+max_sync_time=40
+time_max_limit=1e-5
+time_rms_limit=5e-6
+freq_max_limit=1e-6
+freq_rms_limit=1e-7
+
+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
diff --git a/test/simulation/202-prefer b/test/simulation/202-prefer
new file mode 100755
index 0000000..57a7fc9
--- /dev/null
+++ b/test/simulation/202-prefer
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+. test.common
+
+# Test fix in commit 4253075a97141edfa62043ab71bd0673587e6629
+
+test_start "prefer option"
+
+servers=3
+client_server_conf="
+server 192.168.123.1
+server 192.168.123.2
+server 192.168.123.3 prefer"
+
+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
diff --git a/test/simulation/test.common b/test/simulation/test.common
index 8aee454..03476fd 100644
--- a/test/simulation/test.common
+++ b/test/simulation/test.common
@@ -18,7 +18,7 @@ export PATH=../../:$PATH
export CLKNETSIM_PATH=clknetsim
# Known working clknetsim revision
-clknetsim_revision=7ea71b32e0caec4d8da4cecc3499b5c87098e137
+clknetsim_revision=1e56224dee1db69c0027e9bd63c2a202d4765959
clknetsim_url=https://github.com/mlichvar/clknetsim/archive/$clknetsim_revision.tar.gz
# Only Linux is supported
@@ -49,6 +49,7 @@ default_base_delay=1e-4
default_jitter=1e-4
default_wander=1e-9
default_refclock_jitter=""
+default_refclock_offset=0.0
default_update_interval=0
default_shift_pll=2
@@ -57,12 +58,14 @@ default_server_strata=1
default_servers=1
default_clients=1
default_peers=0
+default_falsetickers=0
default_server_start=0.0
default_client_start=0.0
default_chronyc_start=1000.0
default_server_step=""
default_client_step=""
+default_client_server_conf=""
default_server_server_options=""
default_client_server_options=""
default_server_peer_options=""
@@ -167,7 +170,7 @@ get_delay_expr() {
}
get_refclock_expr() {
- echo "(* $refclock_jitter (normal))"
+ echo "(+ $refclock_offset (* $refclock_jitter (normal)))"
}
get_chronyd_nodes() {
@@ -190,9 +193,13 @@ get_chronyd_conf() {
done
echo "$server_conf"
else
- for i in $(seq 1 $servers); do
- echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $client_server_options"
- done
+ if [ -n "$client_server_conf" ]; then
+ echo "$client_server_conf"
+ else
+ for i in $(seq 1 $servers); do
+ echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $client_server_options"
+ done
+ fi
for i in $(seq 1 $peers); do
[ $i -eq $peer -o $i -gt $clients ] && continue
echo "peer 192.168.123.$[$servers * ($stratum - 1) + $i] $client_peer_options"
@@ -260,7 +267,7 @@ check_source_selection() {
for i in $(seq $[$servers * $server_strata + 1] $(get_chronyd_nodes)); do
test_message 3 0 "node $i:"
- ! grep -q 'no majority\|no reachable sources' tmp/log.$i && \
+ ! grep -q 'no majority\|no selectable sources' tmp/log.$i && \
grep -q 'Selected source' tmp/log.$i && \
test_ok || test_bad
[ $? -eq 0 ] || ret=1
@@ -397,7 +404,7 @@ run_test() {
step=$server_step
start=$server_start
freq=""
- offset=0.0
+ [ $i -le $falsetickers ] && offset=$i.0 || offset=0.0
elif [ $stratum -le $server_strata ]; then
step=$server_step
start=$server_start
diff --git a/util.c b/util.c
index 08fc0cd..0add5df 100644
--- a/util.c
+++ b/util.c
@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
- * Copyright (C) Miroslav Lichvar 2009, 2012-2013
+ * Copyright (C) Miroslav Lichvar 2009, 2012-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
@@ -238,18 +238,18 @@ char *
UTI_RefidToString(uint32_t ref_id)
{
unsigned int i, j, c;
- char buf[5], *result;
+ char *result;
+
+ result = NEXT_BUFFER;
- for (i = j = 0; i < 4; i++) {
+ for (i = j = 0; i < 4 && i < BUFFER_LENGTH - 1; i++) {
c = (ref_id >> (24 - i * 8)) & 0xff;
if (isprint(c))
- buf[j++] = c;
+ result[j++] = c;
}
- buf[j] = '\0';
+ result[j] = '\0';
- result = NEXT_BUFFER;
- snprintf(result, BUFFER_LENGTH, "%s", buf);
return result;
}
@@ -277,7 +277,7 @@ UTI_IPToString(IPAddr *addr)
break;
case IPADDR_INET6:
ip6 = addr->addr.in6;
-#ifdef HAVE_IPV6
+#ifdef FEAT_IPV6
inet_ntop(AF_INET6, ip6, result, BUFFER_LENGTH);
#else
snprintf(result, BUFFER_LENGTH, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
@@ -296,7 +296,7 @@ UTI_IPToString(IPAddr *addr)
int
UTI_StringToIP(const char *addr, IPAddr *ip)
{
-#ifdef HAVE_IPV6
+#ifdef FEAT_IPV6
struct in_addr in4;
struct in6_addr in6;
@@ -426,6 +426,65 @@ UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask)
/* ================================================== */
+void
+UTI_SockaddrToIPAndPort(struct sockaddr *sa, IPAddr *ip, unsigned short *port)
+{
+ switch (sa->sa_family) {
+ case AF_INET:
+ ip->family = IPADDR_INET4;
+ ip->addr.in4 = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
+ *port = ntohs(((struct sockaddr_in *)sa)->sin_port);
+ break;
+#ifdef FEAT_IPV6
+ case AF_INET6:
+ ip->family = IPADDR_INET6;
+ memcpy(ip->addr.in6, ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr,
+ sizeof (ip->addr.in6));
+ *port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+ break;
+#endif
+ default:
+ ip->family = IPADDR_UNSPEC;
+ *port = 0;
+ }
+}
+
+/* ================================================== */
+
+int
+UTI_IPAndPortToSockaddr(IPAddr *ip, unsigned short port, struct sockaddr *sa)
+{
+ switch (ip->family) {
+ case IPADDR_INET4:
+ memset(sa, 0, sizeof (struct sockaddr_in));
+ sa->sa_family = AF_INET;
+ ((struct sockaddr_in *)sa)->sin_addr.s_addr = htonl(ip->addr.in4);
+ ((struct sockaddr_in *)sa)->sin_port = htons(port);
+#ifdef SIN6_LEN
+ ((struct sockaddr_in *)sa)->sin_len = sizeof (struct sockaddr_in);
+#endif
+ return sizeof (struct sockaddr_in);
+#ifdef FEAT_IPV6
+ case IPADDR_INET6:
+ memset(sa, 0, sizeof (struct sockaddr_in6));
+ sa->sa_family = AF_INET6;
+ memcpy(((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr, ip->addr.in6,
+ sizeof (ip->addr.in6));
+ ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
+#ifdef SIN6_LEN
+ ((struct sockaddr_in6 *)sa)->sin6_len = sizeof (struct sockaddr_in6);
+#endif
+ return sizeof (struct sockaddr_in6);
+#endif
+ default:
+ memset(sa, 0, sizeof (struct sockaddr));
+ sa->sa_family = AF_UNSPEC;
+ return 0;
+ }
+}
+
+/* ================================================== */
+
char *
UTI_TimeToLogForm(time_t t)
{
@@ -490,7 +549,7 @@ UTI_DoubleToInt32(double x)
/* ================================================== */
-/* Seconds part of RFC1305 timestamp correponding to the origin of the
+/* Seconds part of NTP timestamp correponding to the origin of the
struct timeval format. */
#define JAN_1970 0x83aa7e80UL
@@ -547,6 +606,59 @@ UTI_Int64ToTimeval(NTP_int64 *src,
/* ================================================== */
+/* Maximum offset between two sane times */
+#define MAX_OFFSET 4294967296.0
+
+/* Minimum allowed distance from maximum 32-bit time_t */
+#define MIN_ENDOFTIME_DISTANCE (365 * 24 * 3600)
+
+int
+UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
+{
+ double t;
+
+ /* Handle nan correctly here */
+ if (!(offset > -MAX_OFFSET && offset < MAX_OFFSET))
+ return 0;
+
+ UTI_TimevalToDouble(tv, &t);
+ t += offset;
+
+ /* Time before 1970 is not considered valid */
+ if (t < 0.0)
+ return 0;
+
+#ifdef HAVE_LONG_TIME_T
+ /* Check if it's in the interval to which NTP time is mapped */
+ if (t < (double)NTP_ERA_SPLIT || t > (double)(NTP_ERA_SPLIT + (1LL << 32)))
+ return 0;
+#else
+ /* Don't get too close to 32-bit time_t overflow */
+ if (t > (double)(0x7fffffff - MIN_ENDOFTIME_DISTANCE))
+ return 0;
+#endif
+
+ return 1;
+}
+
+/* ================================================== */
+
+double
+UTI_Log2ToDouble(int l)
+{
+ if (l >= 0) {
+ if (l > 31)
+ l = 31;
+ return 1 << l;
+ } else {
+ if (l < -31)
+ l = -31;
+ return 1.0 / (1 << -l);
+ }
+}
+
+/* ================================================== */
+
void
UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest)
{
@@ -611,7 +723,11 @@ UTI_FloatHostToNetwork(double x)
if (x < 0.0) {
x = -x;
neg = 1;
+ } else if (x >= 0.0) {
+ neg = 0;
} else {
+ /* Save NaN as zero */
+ x = 0.0;
neg = 0;
}
diff --git a/util.h b/util.h
index a0a688d..6e9fdd1 100644
--- a/util.h
+++ b/util.h
@@ -86,6 +86,9 @@ extern void UTI_IPHostToNetwork(IPAddr *src, IPAddr *dest);
extern void UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest);
extern int UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask);
+extern void UTI_SockaddrToIPAndPort(struct sockaddr *sa, IPAddr *ip, unsigned short *port);
+extern int UTI_IPAndPortToSockaddr(IPAddr *ip, unsigned short port, struct sockaddr *sa);
+
extern char *UTI_TimeToLogForm(time_t t);
/* Adjust time following a frequency/offset change */
@@ -101,6 +104,12 @@ extern void UTI_TimevalToInt64(struct timeval *src, NTP_int64 *dest, uint32_t fu
extern void UTI_Int64ToTimeval(NTP_int64 *src, struct timeval *dest);
+/* Check if time + offset is sane */
+extern int UTI_IsTimeOffsetSane(struct timeval *tv, double offset);
+
+/* Get 2 raised to power of a signed integer */
+extern double UTI_Log2ToDouble(int l);
+
extern void UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest);
extern void UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest);
diff --git a/version.txt b/version.txt
index 6bae540..3e3c2f1 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-1.31.1
+2.1.1
diff --git a/wrap_adjtimex.c b/wrap_adjtimex.c
index 8172c5f..50c4ab7 100644
--- a/wrap_adjtimex.c
+++ b/wrap_adjtimex.c
@@ -22,18 +22,33 @@
=======================================================================
- This is a wrapper around the Linux adjtimex system call. It isolates the
- inclusion of <linux/adjtimex.h> from the need to include other header files,
- many of which conflict with those in <linux/...> on some recent distributions
- (as of Jul 2000) using kernels around 2.2.16 onwards.
+ This is a wrapper around the Linux adjtimex system call.
*/
#include "config.h"
-#include "chrony_timex.h"
#include "wrap_adjtimex.h"
+#include <sys/timex.h>
+
+/* Definitions used if missing in the system headers */
+#ifndef ADJ_TAI
+#define ADJ_TAI 0x0080 /* set TAI offset */
+#endif
+#ifndef ADJ_SETOFFSET
+#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
+#endif
+#ifndef ADJ_NANO
+#define ADJ_NANO 0x2000 /* select nanosecond resolution */
+#endif
+#ifndef ADJ_OFFSET_SS_READ
+#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
+#endif
+
+/* Frequency offset scale (shift) */
+#define SHIFT_USEC 16
+
static int status = 0;
int
@@ -56,7 +71,7 @@ TMX_ResetOffset(void)
/* Set status back */
txc.modes = ADJ_STATUS;
- txc.modes = status;
+ txc.status = status;
if (adjtimex(&txc) < 0)
return -1;
@@ -68,19 +83,11 @@ TMX_SetFrequency(double *freq, long tick)
{
struct timex txc;
- txc.modes = ADJ_TICK | ADJ_FREQUENCY | ADJ_STATUS;
+ txc.modes = ADJ_TICK | ADJ_FREQUENCY;
txc.freq = (long)(*freq * (double)(1 << SHIFT_USEC));
*freq = txc.freq / (double)(1 << SHIFT_USEC);
txc.tick = tick;
- txc.status = status;
-
- if (!(status & STA_UNSYNC)) {
- /* maxerror has to be reset periodically to prevent kernel
- from enabling UNSYNC flag */
- txc.modes |= ADJ_MAXERROR;
- txc.maxerror = 0;
- }
return adjtimex(&txc);
}
@@ -98,51 +105,6 @@ TMX_GetFrequency(double *freq, long *tick)
}
int
-TMX_ReadCurrentParams(struct tmx_params *params)
-{
- struct timex txc;
- int result;
-
- txc.modes = 0; /* pure read */
- result = adjtimex(&txc);
-
- params->tick = txc.tick;
- params->offset = txc.offset;
- params->freq = txc.freq;
- params->dfreq = txc.freq / (double)(1 << SHIFT_USEC);
- params->maxerror = txc.maxerror;
- params->esterror = txc.esterror;
-
- params->sta_pll = !!(txc.status & STA_PLL);
- params->sta_ppsfreq = !!(txc.status & STA_PPSFREQ);
- params->sta_ppstime = !!(txc.status & STA_PPSTIME);
- params->sta_fll = !!(txc.status & STA_FLL);
- params->sta_ins = !!(txc.status & STA_INS);
- params->sta_del = !!(txc.status & STA_DEL);
- params->sta_unsync = !!(txc.status & STA_UNSYNC);
- params->sta_freqhold = !!(txc.status & STA_FREQHOLD);
- params->sta_ppssignal = !!(txc.status & STA_PPSSIGNAL);
- params->sta_ppsjitter = !!(txc.status & STA_PPSJITTER);
- params->sta_ppswander = !!(txc.status & STA_PPSWANDER);
- params->sta_ppserror = !!(txc.status & STA_PPSERROR);
- params->sta_clockerr = !!(txc.status & STA_CLOCKERR);
-
- params->constant = txc.constant;
- params->precision = txc.precision;
- params->tolerance = txc.tolerance;
- params->ppsfreq = txc.ppsfreq;
- params->jitter = txc.jitter;
- params->shift = txc.shift;
- params->stabil = txc.stabil;
- params->jitcnt = txc.jitcnt;
- params->calcnt = txc.calcnt;
- params->errcnt = txc.errcnt;
- params->stbcnt = txc.stbcnt;
-
- return result;
-}
-
-int
TMX_SetLeap(int leap)
{
struct timex txc;
@@ -161,7 +123,29 @@ TMX_SetLeap(int leap)
return adjtimex(&txc);
}
-int TMX_SetSync(int sync)
+int
+TMX_GetLeap(int *leap)
+{
+ struct timex txc;
+
+ txc.modes = 0;
+ if (adjtimex(&txc) < 0)
+ return -1;
+
+ status &= ~(STA_INS | STA_DEL);
+ status |= txc.status & (STA_INS | STA_DEL);
+
+ if (status & STA_INS)
+ *leap = 1;
+ else if (status & STA_DEL)
+ *leap = -1;
+ else
+ *leap = 0;
+
+ return 0;
+}
+
+int TMX_SetSync(int sync, double est_error, double max_error)
{
struct timex txc;
@@ -171,8 +155,10 @@ int TMX_SetSync(int sync)
status |= STA_UNSYNC;
}
- txc.modes = ADJ_STATUS;
+ txc.modes = ADJ_STATUS | ADJ_ESTERROR | ADJ_MAXERROR;
txc.status = status;
+ txc.esterror = est_error * 1.0e6;
+ txc.maxerror = max_error * 1.0e6;
return adjtimex(&txc);
}
@@ -207,12 +193,12 @@ TMX_ApplyStepOffset(double offset)
struct timex txc;
txc.modes = ADJ_SETOFFSET | ADJ_NANO;
- if (offset >= 0) {
- txc.time.tv_sec = offset;
- } else {
- txc.time.tv_sec = offset - 1;
- }
+ txc.time.tv_sec = offset;
txc.time.tv_usec = 1.0e9 * (offset - txc.time.tv_sec);
+ if (txc.time.tv_usec < 0) {
+ txc.time.tv_sec--;
+ txc.time.tv_usec += 1000000000;
+ }
return adjtimex(&txc);
}
diff --git a/wrap_adjtimex.h b/wrap_adjtimex.h
index e7913b7..23587a3 100644
--- a/wrap_adjtimex.h
+++ b/wrap_adjtimex.h
@@ -27,49 +27,12 @@
#ifndef GOT_WRAP_ADJTIMEX_H
#define GOT_WRAP_ADJTIMEX_H
-/* Cut-down version of struct timex */
-struct tmx_params {
- long tick;
- long offset;
- long freq;
- double dfreq;
- long maxerror;
- long esterror;
-
- unsigned sta_pll:1;
- unsigned sta_ppsfreq:1;
- unsigned sta_ppstime:1;
- unsigned sta_fll:1;
- unsigned sta_ins:1;
- unsigned sta_del:1;
- unsigned sta_unsync:1;
- unsigned sta_freqhold:1;
- unsigned sta_ppssignal:1;
- unsigned sta_ppsjitter:1;
- unsigned sta_ppswander:1;
- unsigned sta_ppserror:1;
- unsigned sta_clockerr:1;
-
- int status;
- long constant;
- long precision;
- long tolerance;
- long ppsfreq;
- long jitter;
- int shift;
- long stabil;
- long jitcnt;
- long calcnt;
- long errcnt;
- long stbcnt;
-};
-
int TMX_ResetOffset(void);
int TMX_SetFrequency(double *freq, long tick);
int TMX_GetFrequency(double *freq, long *tick);
-int TMX_ReadCurrentParams(struct tmx_params *params);
int TMX_SetLeap(int leap);
-int TMX_SetSync(int sync);
+int TMX_GetLeap(int *leap);
+int TMX_SetSync(int sync, double est_error, double max_error);
int TMX_TestStepOffset(void);
int TMX_ApplyStepOffset(double offset);