summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 18:43:21 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 18:43:21 +0000
commit104f986b0650b8f93540785d2bcf486905e49b62 (patch)
tree2b2ae5113d9b57425d4bb3f726e325316b87e00a
parentInitial commit. (diff)
downloadchrony-upstream/3.4.tar.xz
chrony-upstream/3.4.zip
Adding upstream version 3.4.upstream/3.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--COPYING339
-rw-r--r--FAQ541
-rw-r--r--INSTALL174
-rw-r--r--Makefile.in136
-rw-r--r--NEWS836
-rw-r--r--README239
-rw-r--r--addressing.h62
-rw-r--r--addrfilt.c403
-rw-r--r--addrfilt.h80
-rw-r--r--array.c130
-rw-r--r--array.h56
-rw-r--r--candm.h726
-rw-r--r--client.c3290
-rw-r--r--clientlog.c695
-rw-r--r--clientlog.h50
-rw-r--r--cmdmon.c1724
-rw-r--r--cmdmon.h40
-rw-r--r--cmdparse.c289
-rw-r--r--cmdparse.h54
-rw-r--r--conf.c2036
-rw-r--r--conf.h142
-rwxr-xr-xconfigure1007
-rw-r--r--contrib/andrew_bishop_1114
-rw-r--r--contrib/andrew_bishop_295
-rw-r--r--contrib/bryan_christianson_1/README.txt103
-rwxr-xr-xcontrib/bryan_christianson_1/chronylogrotate.sh58
-rw-r--r--contrib/bryan_christianson_1/org.tuxfamily.chronyc.plist22
-rw-r--r--contrib/bryan_christianson_1/org.tuxfamily.chronyd.plist19
-rw-r--r--contrib/erik_bryer_165
-rw-r--r--contrib/ken_gillett_1100
-rw-r--r--contrib/stephan_boettcher_1162
-rw-r--r--contrib/wolfgang_weisselberg1118
-rw-r--r--doc/Makefile.in76
-rw-r--r--doc/chrony.conf.adoc2460
-rw-r--r--doc/chrony.conf.man.in3981
-rw-r--r--doc/chronyc.adoc1224
-rw-r--r--doc/chronyc.man.in1914
-rw-r--r--doc/chronyd.adoc186
-rw-r--r--doc/chronyd.man.in211
-rw-r--r--doc/faq.adoc547
-rw-r--r--doc/installation.adoc217
-rw-r--r--examples/chrony-wait.service18
-rw-r--r--examples/chrony.conf.example112
-rw-r--r--examples/chrony.conf.example238
-rw-r--r--examples/chrony.conf.example3304
-rw-r--r--examples/chrony.keys.example13
-rw-r--r--examples/chrony.logrotate8
-rw-r--r--examples/chrony.nm-dispatcher15
-rw-r--r--examples/chronyd.service18
-rw-r--r--getdate.c2713
-rw-r--r--getdate.h28
-rw-r--r--getdate.y1044
-rw-r--r--hash.h43
-rw-r--r--hash_intmd5.c68
-rw-r--r--hash_nettle.c120
-rw-r--r--hash_nss.c109
-rw-r--r--hash_tomcrypt.c133
-rw-r--r--hwclock.c227
-rw-r--r--hwclock.h49
-rw-r--r--keys.c413
-rw-r--r--keys.h48
-rw-r--r--local.c748
-rw-r--r--local.h221
-rw-r--r--localp.h74
-rw-r--r--logging.c330
-rw-r--r--logging.h125
-rw-r--r--main.c623
-rw-r--r--main.h35
-rw-r--r--manual.c331
-rw-r--r--manual.h46
-rw-r--r--md5.c322
-rw-r--r--md5.h56
-rw-r--r--memory.c93
-rw-r--r--memory.h45
-rw-r--r--nameserv.c200
-rw-r--r--nameserv.h52
-rw-r--r--nameserv_async.c133
-rw-r--r--nameserv_async.h40
-rw-r--r--ntp.h139
-rw-r--r--ntp_core.c2662
-rw-r--r--ntp_core.h139
-rw-r--r--ntp_io.c899
-rw-r--r--ntp_io.h63
-rw-r--r--ntp_io_linux.c863
-rw-r--r--ntp_io_linux.h45
-rw-r--r--ntp_signd.c379
-rw-r--r--ntp_signd.h44
-rw-r--r--ntp_sources.c1137
-rw-r--r--ntp_sources.h131
-rw-r--r--pktlength.c205
-rw-r--r--pktlength.h40
-rw-r--r--privops.c731
-rw-r--r--privops.h77
-rw-r--r--refclock.c738
-rw-r--r--refclock.h83
-rw-r--r--refclock_phc.c176
-rw-r--r--refclock_pps.c169
-rw-r--r--refclock_shm.c133
-rw-r--r--refclock_sock.c144
-rw-r--r--reference.c1382
-rw-r--r--reference.h193
-rw-r--r--regress.c704
-rw-r--r--regress.h137
-rw-r--r--reports.h163
-rw-r--r--rtc.c240
-rw-r--r--rtc.h45
-rw-r--r--rtc_linux.c1129
-rw-r--r--rtc_linux.h45
-rw-r--r--samplefilt.c453
-rw-r--r--samplefilt.h49
-rw-r--r--sched.c798
-rw-r--r--sched.h89
-rw-r--r--smooth.c364
-rw-r--r--smooth.h48
-rw-r--r--sources.c1392
-rw-r--r--sources.h127
-rw-r--r--sourcestats.c1040
-rw-r--r--sourcestats.h136
-rw-r--r--srcparams.h85
-rw-r--r--stubs.c412
-rw-r--r--sys.c147
-rw-r--r--sys.h48
-rw-r--r--sys_generic.c422
-rw-r--r--sys_generic.h46
-rw-r--r--sys_linux.c902
-rw-r--r--sys_linux.h54
-rw-r--r--sys_macosx.c519
-rw-r--r--sys_macosx.h38
-rw-r--r--sys_netbsd.c154
-rw-r--r--sys_netbsd.h37
-rw-r--r--sys_null.c140
-rw-r--r--sys_null.h34
-rw-r--r--sys_solaris.c63
-rw-r--r--sys_solaris.h36
-rw-r--r--sys_timex.c266
-rw-r--r--sys_timex.h48
-rw-r--r--sysincl.h76
-rw-r--r--tempcomp.c180
-rw-r--r--tempcomp.h29
-rwxr-xr-xtest/compilation/001-features30
-rwxr-xr-xtest/compilation/002-scanbuild15
-rwxr-xr-xtest/compilation/003-sanitizers87
-rw-r--r--test/kernel/Makefile7
-rw-r--r--test/kernel/adjtime.c185
-rw-r--r--test/kernel/ntpadjtime.c75
-rwxr-xr-xtest/simulation/001-defaults13
-rwxr-xr-xtest/simulation/002-largenetwork22
-rwxr-xr-xtest/simulation/003-largefreqoffset19
-rwxr-xr-xtest/simulation/004-largetimeoffset18
-rwxr-xr-xtest/simulation/005-externalstep46
-rwxr-xr-xtest/simulation/006-largejitter21
-rwxr-xr-xtest/simulation/007-largewander20
-rwxr-xr-xtest/simulation/008-ntpera40
-rwxr-xr-xtest/simulation/009-sourceselection40
-rwxr-xr-xtest/simulation/010-multrecv17
-rwxr-xr-xtest/simulation/011-asymjitter18
-rwxr-xr-xtest/simulation/012-daemonts15
-rwxr-xr-xtest/simulation/101-poll30
-rwxr-xr-xtest/simulation/102-iburst23
-rwxr-xr-xtest/simulation/103-initstepslew32
-rwxr-xr-xtest/simulation/104-driftfile23
-rwxr-xr-xtest/simulation/105-ntpauth87
-rwxr-xr-xtest/simulation/106-refclock30
-rwxr-xr-xtest/simulation/107-allowdeny46
-rwxr-xr-xtest/simulation/108-peer54
-rwxr-xr-xtest/simulation/109-makestep41
-rwxr-xr-xtest/simulation/110-chronyc163
-rwxr-xr-xtest/simulation/111-knownclient17
-rwxr-xr-xtest/simulation/112-port55
-rwxr-xr-xtest/simulation/113-leapsecond58
-rwxr-xr-xtest/simulation/114-presend25
-rwxr-xr-xtest/simulation/115-cmdmontime24
-rwxr-xr-xtest/simulation/116-minsources24
-rwxr-xr-xtest/simulation/117-fallbackdrift24
-rwxr-xr-xtest/simulation/118-maxdelay28
-rwxr-xr-xtest/simulation/119-smoothtime79
-rwxr-xr-xtest/simulation/120-selectoptions68
-rwxr-xr-xtest/simulation/121-orphan24
-rwxr-xr-xtest/simulation/122-xleave37
-rwxr-xr-xtest/simulation/123-mindelay27
-rwxr-xr-xtest/simulation/124-tai42
-rwxr-xr-xtest/simulation/125-packetloss29
-rwxr-xr-xtest/simulation/126-burst45
-rwxr-xr-xtest/simulation/127-filter19
-rwxr-xr-xtest/simulation/128-nocontrol25
-rwxr-xr-xtest/simulation/129-reload26
-rwxr-xr-xtest/simulation/130-quit23
-rwxr-xr-xtest/simulation/131-maxchange20
-rwxr-xr-xtest/simulation/132-logchange21
-rwxr-xr-xtest/simulation/133-hwtimestamp32
-rwxr-xr-xtest/simulation/134-log30
-rwxr-xr-xtest/simulation/135-ratelimit18
-rwxr-xr-xtest/simulation/136-broadcast16
-rwxr-xr-xtest/simulation/201-freqaccumulation35
-rwxr-xr-xtest/simulation/202-prefer21
-rw-r--r--test/simulation/README11
-rwxr-xr-xtest/simulation/run90
-rw-r--r--test/simulation/test.common494
-rw-r--r--test/unit/Makefile.in47
-rw-r--r--test/unit/addrfilt.c83
-rw-r--r--test/unit/clientlog.c84
-rw-r--r--test/unit/hash.c123
-rw-r--r--test/unit/hwclock.c84
-rw-r--r--test/unit/keys.c147
-rw-r--r--test/unit/ntp_core.c477
-rw-r--r--test/unit/ntp_core.keys6
-rw-r--r--test/unit/ntp_sources.c100
-rw-r--r--test/unit/regress.c119
-rw-r--r--test/unit/samplefilt.c117
-rw-r--r--test/unit/smooth.c63
-rw-r--r--test/unit/sources.c142
-rw-r--r--test/unit/test.c179
-rw-r--r--test/unit/test.h46
-rw-r--r--test/unit/util.c267
-rw-r--r--util.c1260
-rw-r--r--util.h205
-rw-r--r--version.txt1
217 files changed, 61137 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ 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/FAQ b/FAQ
new file mode 100644
index 0000000..089b3b8
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,541 @@
+Frequently Asked Questions
+
+Table of Contents
+
+ o 1. chrony compared to other programs
+ ? 1.1. How does chrony compare to ntpd?
+ o 2. Configuration issues
+ ? 2.1. What is the minimum recommended configuration for an NTP client?
+ ? 2.2. How do I make an NTP server from an NTP client?
+ ? 2.3. I have several computers on a LAN. Should be all clients of an
+ external server?
+ ? 2.4. Must I specify servers by IP address if DNS is not available on
+ chronyd start?
+ ? 2.5. How can I make chronyd more secure?
+ ? 2.6. How can I improve the accuracy of the system clock with NTP
+ sources?
+ ? 2.7. Does chronyd have an ntpdate mode?
+ ? 2.8. Can chronyd be configured to control the clock like ntpd?
+ ? 2.9. What happened to the commandkey and generatecommandkey directives?
+ o 3. Computer is not synchronising
+ ? 3.1. Behind a firewall?
+ ? 3.2. Are NTP servers specified with the offline option?
+ ? 3.3. Is chronyd allowed to step the system clock?
+ ? 3.4. Using a Windows NTP server?
+ ? 3.5. Using a PPS reference clock?
+ o 4. Issues with chronyc
+ ? 4.1. I keep getting the error 506 Cannot talk to daemon
+ ? 4.2. I keep getting the error 501 Not authorised
+ ? 4.3. Why does chronyc tracking always print an IPv4 address as
+ reference ID?
+ ? 4.4. Is the chronyc / chronyd protocol documented anywhere?
+ o 5. Real-time clock issues
+ ? 5.1. What is the real-time clock (RTC)?
+ ? 5.2. I want to use chronyd's RTC support. Must I disable hwclock?
+ ? 5.3. I just keep getting the 513 RTC driver not running message
+ ? 5.4. I get Could not open /dev/rtc, Device or resource busy in my
+ syslog file
+ ? 5.5. What if my computer does not have an RTC or backup battery?
+ o 6. NTP-specific issues
+ ? 6.1. Can chronyd be driven from broadcast/multicast NTP servers?
+ ? 6.2. Can chronyd transmit broadcast NTP packets?
+ ? 6.3. Can chronyd keep the system clock a fixed offset away from real
+ time?
+ ? 6.4. What happens if the network connection is dropped without using
+ chronyc's offline command first?
+ o 7. Operating systems
+ ? 7.1. Does chrony support Windows?
+ ? 7.2. Are there any plans to support Windows?
+
+1. chrony compared to other programs
+
+1.1. How does chrony compare to ntpd?
+
+chronyd was designed to work well in a wide range of conditions and it can
+usually synchronise the system clock faster and with better time accuracy. It
+doesn't implement some of the less useful NTP modes like broadcast client or
+multicast server/client.
+
+If your computer is connected to the Internet only for few minutes at a time,
+the network connection is often congested, you turn your computer off or
+suspend it frequently, the clock is not very stable (e.g. there are rapid
+changes in the temperature or it's a virtual machine), or you want to use NTP
+on an isolated network with no hardware reference clocks in sight, chrony will
+probably work much better for you.
+
+For a more detailed comparison of features and performance, see the comparison
+page on the chrony website.
+
+2. Configuration issues
+
+2.1. What is the minimum recommended configuration for an NTP client?
+
+First, the client needs to know which NTP servers it should ask for the current
+time. They are specified by the server or pool directive. The pool directive
+can be used for names that resolve to multiple addresses. For good reliability
+the client should have at least three servers. The iburst option speeds up the
+initial synchronisation.
+
+To stabilise the initial synchronisation on the next start, the estimated drift
+of the system clock is saved to a file specified by the driftfile directive.
+
+If the system clock can be far from the true time after boot for any reason,
+chronyd should be allowed to correct it quickly by stepping instead of slewing,
+which would take a very long time. The makestep directive does that.
+
+In order to keep the real-time clock (RTC) close to the true time, so the
+system time is reasonably close to the true time when it's initialised on the
+next boot from the RTC, the rtcsync directive enables a mode in which the
+system time is periodically copied to the RTC. It is supported on Linux and
+macOS.
+
+If you want to use public NTP servers from the pool.ntp.org project, the
+minimal chrony.conf file could be:
+
+pool pool.ntp.org iburst
+driftfile /var/lib/chrony/drift
+makestep 1 3
+rtcsync
+
+2.2. How do I make an NTP server from an NTP client?
+
+You need to add an allow directive to the chrony.conf file in order to open the
+NTP port and allow chronyd to reply to client requests. allow with no specified
+subnet allows access from all IPv4 and IPv6 addresses.
+
+2.3. 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 server, with the
+others as clients of it. Add a local directive to the server's chrony.conf
+file. This configuration will be better because
+
+ o the load on the external connection is less
+
+ o the load on the external NTP server(s) is less
+
+ o if your external connection goes down, the computers on the LAN will
+ maintain a common time with each other.
+
+2.4. 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 names
+specified by the server, pool, and peer directives in an increasing interval
+until it succeeds. The online command can be issued from chronyc to force
+chronyd to try to resolve the names immediately.
+
+2.5. 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 or you need to run chronyc only under
+the root or chrony user (which can access chronyd through a Unix domain socket
+since version 2.2), you can disable the internet command sockets completely by
+adding cmdport 0 to the configuration file.
+
+You can specify an unprivileged user with the -u option, or the user directive
+in the chrony.conf file, to which chronyd will switch after start in order to
+drop root privileges. The configure script has a --with-user option, which sets
+the default user. On Linux, chronyd needs to be compiled with support for the
+libcap library. On other systems, chronyd forks into two processes. The child
+process retains root privileges, but can only perform a very limited range of
+privileged system calls on behalf of the parent.
+
+Also, if chronyd is compiled with support for the Linux secure computing
+(seccomp) facility, you can enable a system call filter with the -F option. It
+will significantly reduce the kernel attack surface and possibly prevent kernel
+exploits from the chronyd process if it's compromised. It's recommended to
+enable the filter only when it's known to work on the version of the system
+where chrony is installed as the filter needs to allow also system calls made
+from libraries that chronyd is using (e.g. libc) and different versions or
+implementations of the libraries may make different system calls. If the filter
+is missing some system call, chronyd could be killed even in normal operation.
+
+2.6. 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 servers that serve false time
+and combine measurements from multiple sources.
+
+If you have a network card with hardware timestamping supported on Linux, it
+can be enabled by the hwtimestamp directive in the chrony.conf file. It should
+make local receive and transmit timestamps of NTP packets much more accurate.
+
+There are also useful options which can be set in the server directive, they
+are minpoll, maxpoll, polltarget, maxdelay, maxdelayratio, maxdelaydevratio,
+and xleave.
+
+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 8 (samples) for polltarget. The default values should be used for general
+servers on the Internet. With your own NTP servers, or if you have permission
+to poll some servers more frequently, setting these options for shorter polling
+intervals may significantly improve the accuracy of the system clock.
+
+The optimal polling interval depends mainly on two factors, stability of the
+network latency and stability of the system clock (which mainly depends on the
+temperature sensitivity of the crystal oscillator and the maximum rate of the
+temperature change).
+
+Generally, if the sourcestats command usually reports a small number of samples
+retained for a source (e.g. fewer than 16), a shorter polling interval should
+be considered. If the number of samples is usually at the maximum of 64, a
+longer polling interval may work better.
+
+An example of the directive for an NTP server on the Internet that you are
+allowed to poll frequently could be
+
+server foo.example.net minpoll 4 maxpoll 6 polltarget 16
+
+An example using shorter polling intervals with 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 an unusally large
+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
+
+If your server supports the interleaved mode (e.g. it is running chronyd), the
+xleave option should be added to the server directive in order to allow the
+server to send the client more accurate transmit timestamps (kernel or
+preferably hardware). For example:
+
+server ntp.local minpoll 2 maxpoll 4 xleave
+
+When combined with local hardware timestamping, good network switches, and even
+shorter polling intervals, a sub-microsecond accuracy and stability of a few
+tens of nanoseconds may be possible. For example:
+
+server ntp.local minpoll 0 maxpoll 0 xleave
+hwtimestamp eth0
+
+If it is acceptable for NTP clients in the network to send requests at an
+excessive rate, a sub-second polling interval may be specified. A median filter
+can be enabled in order to update the clock at a reduced rate with more stable
+measurements. For example:
+
+server ntp.local minpoll -6 maxpoll -6 filter 15 xleave
+hwtimestamp eth0 minpoll -6
+
+2.7. Does chronyd have an ntpdate mode?
+
+Yes. With the -q option chronyd will set the system clock once and exit. With
+the -Q option it will print the measured offset without setting the clock. If
+you don't want to use a configuration file, NTP servers can be specified on the
+command line. For example:
+
+# chronyd -q 'pool pool.ntp.org iburst'
+
+2.8. Can chronyd be configured to control the clock like ntpd?
+
+It is not possible to perfectly emulate ntpd, but there are some options that
+can configure chronyd to behave more like ntpd.
+
+In the following example the minsamples directive slows down the response to
+changes in the frequency and offset of the clock. The maxslewrate and
+corrtimeratio directives reduce the maximum frequency error due to an offset
+correction and the maxdrift directive reduces the maximum assumed frequency
+error of the clock. The makestep directive enables a step threshold and the
+maxchange directive enables a panic threshold. The maxclockerror directive
+increases the minimum dispersion rate.
+
+minsamples 32
+maxslewrate 500
+corrtimeratio 100
+maxdrift 500
+makestep 0.128 -1
+maxchange 1000 1 1
+maxclockerror 15
+
+2.9. What happened to the commandkey and generatecommandkey directives?
+
+They were removed in version 2.2. Authentication is no longer supported in the
+command protocol. Commands that required authentication are now allowed only
+through a Unix domain socket, which is accessible only by the root and chrony
+users. If you need to configure chronyd remotely or locally without the root
+password, please consider using ssh and/or sudo to run chronyc under the root
+or chrony user on the host where chronyd is running.
+
+3. Computer is not synchronising
+
+This is the most common problem. There are a number of reasons, see the
+following questions.
+
+3.1. Behind a firewall?
+
+Check the Reach value printed by the chronyc's sources command. If it's zero,
+it means chronyd did not get any valid responses from the NTP server you are
+trying to use. If there is a firewall between you and the server, the packets
+may be blocked. Try using a tool like wireshark or tcpdump to see if you're
+getting any responses from the server.
+
+When chronyd is receiving responses from the servers, the output of the sources
+command issued few minutes after chronyd start might look like this:
+
+210 Number of sources = 3
+MS Name/IP address Stratum Poll Reach LastRx Last sample
+===============================================================================
+^* foo.example.net 2 6 377 34 +484us[ -157us] +/- 30ms
+^- bar.example.net 2 6 377 34 +33ms[ +32ms] +/- 47ms
+^+ baz.example.net 3 6 377 35 -1397us[-2033us] +/- 60ms
+
+3.2. Are NTP servers specified with the offline option?
+
+Check that you're using chronyc's online and offline commands appropriately.
+The activity command prints the number of sources that are currently online and
+offline. For example:
+
+200 OK
+3 sources online
+0 sources offline
+0 sources doing burst (return to online)
+0 sources doing burst (return to offline)
+0 sources with unknown address
+
+3.3. Is chronyd allowed to step the system clock?
+
+By default, chronyd adjusts the clock gradually by slowing it down or speeding
+it up. If the clock is too far from the true time, it will take a long time to
+correct the error. The System time value printed by the chronyc's tracking
+command is the remaining correction that needs to be applied to the system
+clock.
+
+The makestep directive can be used to allow chronyd to step the clock. For
+example, if chrony.conf had
+
+makestep 1 3
+
+the clock would be stepped in the first three updates if its offset was larger
+than one second. Normally, it's recommended to allow the step only in the first
+few updates, but in some cases (e.g. a computer without an RTC or virtual
+machine which can be suspended and resumed with an incorrect time) it may be
+necessary to allow the step on any clock update. The example above would change
+to
+
+makestep 1 -1
+
+3.4. Using a Windows NTP server?
+
+A common issue with Windows NTP servers is that they report a very large root
+dispersion (e.g. three seconds or more), which causes chronyd to ignore the
+server for being too inaccurate. The sources command may show a valid
+measurement, but the server is not selected for synchronisation. You can check
+the root dispersion of the server with the chronyc's ntpdata command.
+
+The maxdistance value needs to be increased in chrony.conf to enable
+synchronisation to such a server. For example:
+
+maxdistance 16.0
+
+3.5. Using a PPS reference clock?
+
+A pulse-per-second (PPS) reference clock requires a non-PPS time source to
+determine which second of UTC corresponds to each pulse. If it is another
+reference clock specified with the lock option in the refclock directive, the
+offset between the two reference clocks must be smaller than 0.2 seconds in
+order for the PPS reference clock to work. With NMEA reference clocks it is
+common to have a larger offset. It needs to be corrected with the offset
+option.
+
+One approach to find out a good value of the offset option is to configure the
+reference clocks with the noselect option and compare them to an NTP server.
+For example, if the sourcestats command showed
+
+Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
+==============================================================================
+PPS0 0 0 0 +0.000 2000.000 +0ns 4000ms
+NMEA 58 30 231 -96.494 38.406 +504ms 6080us
+foo.example.net 7 3 200 -2.991 16.141 -107us 492us
+
+the offset of the NMEA source would need to be increased by about 0.504
+seconds. It does not have to be very accurate. As long as the offset of the
+NMEA reference clock stays below 0.2 seconds, the PPS reference clock should be
+able to determine the seconds corresponding to the pulses and allow the samples
+to be used for synchronisation.
+
+4. Issues with chronyc
+
+4.1. I keep getting the error 506 Cannot talk to daemon
+
+When accessing chronyd remotely, make sure that the chrony.conf file (on the
+computer where chronyd is running) has a cmdallow entry for the computer you
+are running chronyc on and an appropriate bindcmdaddress directive. This isn't
+necessary for localhost.
+
+Perhaps chronyd is not running. Try using the ps command (e.g. on Linux, ps
+-auxw) to see if it's running. Or try netstat -a and see if the ports 123/udp
+and 323/udp are listening. If chronyd is not running, you may have a problem
+with the way you are trying to start it (e.g. at boot time).
+
+Perhaps you have a firewall set up in a way that blocks packets on port 323/
+udp. You need to amend the firewall configuration in this case.
+
+4.2. I keep getting the error 501 Not authorised
+
+Since version 2.2, the password command doesn't do anything and chronyc needs
+to run locally under the root or chrony user, which are allowed to access the
+chronyd's Unix domain command socket.
+
+With older versions, you need to authenticate with the password command first
+or use the -a option to authenticate automatically on start. The configuration
+file needs to specify a file which contains keys (keyfile directive) and which
+key in the key file should be used for chronyc authentication (commandkey
+directive).
+
+4.3. Why does chronyc tracking always print an IPv4 address as reference ID?
+
+The reference ID is a 32-bit value and in versions before 3.0 it was printed in
+quad-dotted notation, even if the reference source did not actually have an
+IPv4 address. For IPv4 addresses, the reference ID is equal to the address, but
+for IPv6 addresses it is the first 32 bits of the MD5 sum of the address. For
+reference clocks, the reference ID is the value specified with the refid option
+in the refclock directive.
+
+Since version 3.0, the reference ID is printed as a hexadecimal number to avoid
+confusion with IPv4 addresses.
+
+If you need to get the IP address of the current reference source, use the -n
+option to disable resolving of IP addresses and read the second field (printed
+in parentheses) on the Reference ID line.
+
+4.4. Is the chronyc / chronyd protocol documented anywhere?
+
+Only by the source code. See cmdmon.c (chronyd side) and client.c (chronyc
+side).
+
+5. Real-time clock issues
+
+5.1. What is the real-time clock (RTC)?
+
+This is the clock which keeps the time even when your computer is turned off.
+It is used to initialise the system clock on boot. It normally doesn't drift
+more than few seconds per day.
+
+There are two approaches how chronyd can work with it. One is to use the
+rtcsync directive, which tells chronyd to enable a kernel mode which sets the
+RTC from the system clock every 11 minutes. chronyd itself won't touch the RTC.
+If the computer is not turned off for a long time, the RTC should still be
+close to the true time when the system clock will be initialised from it on the
+next boot.
+
+The other option is to use the rtcfile directive, which tells chronyd to
+monitor the rate at which the RTC gains or loses time. When chronyd is started
+with the -s option on the next boot, it will set the system time from the RTC
+and also compensate for the drift it has measured previously. The rtcautotrim
+directive can be used to keep the RTC close to the true time, but it's not
+strictly necessary if its only purpose is to set the system clock when chronyd
+is started on boot. See the documentation for details.
+
+5.2. I want to use chronyd's RTC support. Must I disable hwclock?
+
+The hwclock program is often set-up by default in the boot and shutdown scripts
+with many Linux installations. With the kernel RTC synchronisation (rtcsync
+directive), the RTC will be set also every 11 minutes as long as the system
+clock is synchronised. If you want to use chronyd's RTC monitoring (rtcfile
+directive), it's important 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 started with the -s option 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.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
+
+ o an RTC in your computer
+
+ o a Linux kernel with enabled RTC support
+
+ o an rtcfile directive in your chrony.conf file
+
+5.4. 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.5. What if my computer does not have an RTC or backup battery?
+
+In this case you can still use the -s option to set the system clock to the
+last modification time of the drift file, which should correspond to the system
+time when chronyd was previously stopped. The initial system time will be
+increasing across reboots and applications started after chronyd will not
+observe backward steps.
+
+6. NTP-specific issues
+
+6.1. Can chronyd be driven from broadcast/multicast NTP servers?
+
+No, the broadcast/multicast client mode is not supported and there is currently
+no plan to implement it. While the mode may be useful to simplify configuration
+of clients in large networks, it is inherently less accurate and less secure
+(even with authentication) than the ordinary client/server mode.
+
+When configuring a large number of clients in a network, it is recommended to
+use the pool directive with a DNS name which resolves to addresses of multiple
+NTP servers. The clients will automatically replace the servers when they
+become unreachable, or otherwise unsuitable for synchronisation, with new
+servers from the pool.
+
+Even with very modest hardware, an NTP server can serve time to hundreds of
+thousands of clients using the ordinary client/server mode.
+
+6.2. Can chronyd transmit broadcast NTP packets?
+
+Yes, the broadcast directive can be used to enable the broadcast server mode to
+serve time to clients in the network which support the broadcast client mode
+(it's not supported in chronyd, see the previous question).
+
+6.3. Can chronyd keep the system clock a fixed offset away from real time?
+
+Yes. Starting from version 3.0, an offset can be specified by the offset option
+for all time sources in the chrony.conf file.
+
+6.4. What happens if the network connection is dropped without using chronyc's
+offline command first?
+
+chronyd will keep trying to access the sources that it thinks are online, and
+it will take longer before new measurements are actually made and the clock is
+corrected when the network is connected again. If the sources were set to
+offline, chronyd would make new measurements immediately after issuing the
+online command.
+
+Unless the network connection lasts only few minutes (less than the maximum
+polling interval), the delay is usually not a problem, and it may be acceptable
+to keep all sources online all the time.
+
+7. Operating systems
+
+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 a service.
+
+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.
+
+Last updated 2018-09-19 16:38:15 CEST
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b4ad72f
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,174 @@
+Installation
+
+The software is distributed as source code which has to be compiled. The source
+code is supplied in the form of a gzipped tar file, which unpacks to a
+subdirectory identifying the name and version of the program.
+
+After unpacking the source code, change directory into it, and type
+
+./configure
+
+This is a shell script that automatically determines the system type. There is
+an optional parameter --prefix, which indicates the directory tree where the
+software should be installed. For example,
+
+./configure --prefix=/opt/free
+
+will install the chronyd daemon into /opt/free/sbin and the chronyc control
+program into /opt/free/bin. The default value for the prefix is /usr/local.
+
+The configure script assumes you want to use gcc as your compiler. If you want
+to use a different compiler, you can configure this way:
+
+CC=cc ./configure --prefix=/opt/free
+
+for Bourne-family shells, or
+
+setenv CC cc
+setenv CFLAGS -O
+./configure --prefix=/opt/free
+
+for C-family shells.
+
+If the software cannot (yet) be built on your system, an error message will be
+shown. Otherwise, Makefile will be generated.
+
+On Linux, if development files for the libcap library are available, chronyd
+will be built with support for dropping root privileges. On other systems no
+extra library is needed. The default user which chronyd should run as can be
+specified with the --with-user option of the configure script.
+
+If development files for the POSIX threads library are available, chronyd will
+be built with support for asynchronous resolving of hostnames specified in the
+server, peer, and pool directives. This allows chronyd operating as a server to
+respond to client requests when resolving a hostname. If you don't want to
+enable the support, specify the --disable-asyncdns flag to configure.
+
+If development files for the Nettle, NSS, or libtomcrypt library are available,
+chronyd will be built with support for other cryptographic hash functions than
+MD5, which can be used for NTP authentication with a symmetric key. If you
+don't want to enable the support, specify the --disable-sechash flag to
+configure.
+
+If development files for the editline or readline library are available,
+chronyc will be built with line editing support. If you don't want this,
+specify the --disable-readline flag to configure.
+
+If a timepps.h header is available (e.g. from the LinuxPPS project), chronyd
+will be built with PPS API reference clock driver. If the header is installed
+in a location that isn't normally searched by the compiler, you can add it to
+the searched locations by setting the CPPFLAGS variable to -I/path/to/timepps.
+
+The --help option can be specified to configure to print all options supported
+by the script.
+
+Now type
+
+make
+
+to build the programs.
+
+If you want to build the manual in HTML, type
+
+make docs
+
+Once the programs have been successfully compiled, they need to be installed in
+their target locations. This step normally needs to be performed by the
+superuser, and requires the following command to be entered.
+
+make install
+
+This will install the binaries and man pages.
+
+To install the HTML version of the manual, enter the command
+
+make install-docs
+
+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.
+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
+
+pool pool.ntp.org iburst
+makestep 1.0 3
+rtcsync
+
+Then, chronyd can be run. For security reasons, it's recommended to create an
+unprivileged user for chronyd and specify it with the -u command-line option or
+the user directive in the configuration file, or set the default user with the
+--with-user configure option before building.
+
+Support for system call filtering
+
+chronyd can be built with support for the Linux secure computing (seccomp)
+facility. This requires development files for the libseccomp library and the
+--enable-scfilter option specified to configure. The -F option of chronyd will
+enable a system call filter, which should significantly reduce the kernel
+attack surface and possibly prevent kernel exploits from chronyd if it is
+compromised.
+
+Support for line editing libraries
+
+chronyc can be built with support for line editing, this allows you to use the
+cursor keys to replay and edit old commands. Two libraries are supported which
+provide such functionality, editline and GNU readline.
+
+Please note that readline since version 6.0 is licensed under GPLv3+ which is
+incompatible with chrony's license GPLv2. You should use editline instead if
+you don't want to use older readline versions.
+
+The configure script will automatically enable the line editing support if one
+of the supported libraries is available. If they are both available, the
+editline library will be used.
+
+If you don't want to use it (in which case chronyc will use a minimal command
+line interface), invoke configure like this:
+
+./configure --disable-readline other-options...
+
+If you have editline, readline or ncurses installed in locations that aren't
+normally searched by the compiler and linker, you need to use extra options:
+
+--with-readline-includes=directory_name
+
+ This defines the name of the directory above the one where readline.h is.
+ readline.h is assumed to be in editline or readline subdirectory of the
+ named directory.
+
+--with-readline-library=directory_name
+
+ This defines the directory containing the libedit.a or libedit.so file, or
+ libreadline.a or libreadline.so file.
+
+--with-ncurses-library=directory_name
+
+ This defines the directory containing the libncurses.a or libncurses.so
+ file.
+
+Extra options for package builders
+
+The configure and make procedures have some extra options that may be useful if
+you are building a distribution package for chrony.
+
+The --mandir=DIR option to configure specifies an installation directory for
+the man pages. This overrides the man subdirectory of the argument to the
+--prefix option.
+
+./configure --prefix=/usr --mandir=/usr/share/man
+
+to set both options together.
+
+The final option is the DESTDIR option to the make command. For example, you
+could use the commands
+
+./configure --prefix=/usr --mandir=/usr/share/man
+make all docs
+make install DESTDIR=./tmp
+cd tmp
+tar cvf - . | gzip -9 > chrony.tar.gz
+
+to build a package. When untarred within the root directory, this will install
+the files to the intended final locations.
+
+Last updated 2018-09-19 16:38:15 CEST
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..2d3e67d
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,136 @@
+##################################################
+#
+# chronyd/chronyc - Programs for keeping computer clocks accurate.
+#
+# Copyright (C) Richard P. Curnow 1997-2003
+#
+# 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.
+#
+# =======================================================================
+#
+# Makefile template
+
+SYSCONFDIR=@SYSCONFDIR@
+BINDIR=@BINDIR@
+SBINDIR=@SBINDIR@
+LOCALSTATEDIR=@LOCALSTATEDIR@
+CHRONYVARDIR=@CHRONYVARDIR@
+
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+
+DESTDIR=
+
+HASH_OBJ = @HASH_OBJ@
+
+OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o \
+ reference.o regress.o rtc.o samplefilt.o sched.o sources.o sourcestats.o stubs.o \
+ smooth.o sys.o sys_null.o tempcomp.o util.o $(HASH_OBJ)
+
+EXTRA_OBJS=@EXTRA_OBJECTS@
+
+CLI_OBJS = array.o client.o cmdparse.o getdate.o memory.o nameserv.o \
+ pktlength.o util.o $(HASH_OBJ)
+
+ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS)
+
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+EXTRA_LIBS=@EXTRA_LIBS@
+EXTRA_CLI_LIBS=@EXTRA_CLI_LIBS@
+
+# Until we have a main procedure we can link, just build object files
+# to test compilation
+
+all : chronyd chronyc
+
+chronyd : $(OBJS) $(EXTRA_OBJS)
+ $(CC) $(CFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS)
+
+chronyc : $(CLI_OBJS)
+ $(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_CLI_LIBS)
+
+distclean : clean
+ $(MAKE) -C doc distclean
+ $(MAKE) -C test/unit distclean
+ -rm -f .DS_Store
+ -rm -f Makefile config.h config.log
+
+clean :
+ -rm -f *.o *.s chronyc chronyd core.* *~
+ -rm -f *.gcda *.gcno
+ -rm -rf .deps
+ -rm -rf *.dSYM
+
+getdate.c : getdate.y
+ bison -o getdate.c getdate.y
+
+# This can be used to force regeneration of getdate.c
+getdate :
+ bison -o getdate.c getdate.y
+
+# For install, don't use the install command, because its switches
+# seem to vary between systems.
+
+install: chronyd chronyc
+ [ -d $(DESTDIR)$(SYSCONFDIR) ] || mkdir -p $(DESTDIR)$(SYSCONFDIR)
+ [ -d $(DESTDIR)$(SBINDIR) ] || mkdir -p $(DESTDIR)$(SBINDIR)
+ [ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
+ [ -d $(DESTDIR)$(CHRONYVARDIR) ] || mkdir -p $(DESTDIR)$(CHRONYVARDIR)
+ if [ -f $(DESTDIR)$(SBINDIR)/chronyd ]; then rm -f $(DESTDIR)$(SBINDIR)/chronyd ; fi
+ if [ -f $(DESTDIR)$(BINDIR)/chronyc ]; then rm -f $(DESTDIR)$(BINDIR)/chronyc ; fi
+ cp chronyd $(DESTDIR)$(SBINDIR)/chronyd
+ chmod 755 $(DESTDIR)$(SBINDIR)/chronyd
+ cp chronyc $(DESTDIR)$(BINDIR)/chronyc
+ chmod 755 $(DESTDIR)$(BINDIR)/chronyc
+ $(MAKE) -C doc install
+
+docs :
+ $(MAKE) -C doc docs
+
+install-docs :
+ $(MAKE) -C doc install-docs
+
+%.o : %.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+
+%.s : %.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -S $<
+
+quickcheck : chronyd chronyc
+ $(MAKE) -C test/unit check
+ cd test/simulation && ./run
+
+check : chronyd chronyc
+ $(MAKE) -C test/unit check
+ cd test/simulation && ./run -i 20 -m 2
+
+print-chronyd-objects :
+ @echo $(OBJS) $(EXTRA_OBJS)
+
+Makefile : Makefile.in configure
+ @echo
+ @echo Makefile needs to be regenerated, run ./configure
+ @echo
+ @exit 1
+
+.deps:
+ @mkdir .deps
+
+.deps/%.d: %.c | .deps
+ @$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@
+
+-include $(ALL_OBJS:%.o=.deps/%.d)
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..51a0c22
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,836 @@
+New in version 3.4
+==================
+
+Enhancements
+------------
+* Add filter option to server/pool/peer directive
+* Add minsamples and maxsamples options to hwtimestamp directive
+* Add support for faster frequency adjustments in Linux 4.19
+* Change default pidfile to /var/run/chrony/chronyd.pid to allow
+ chronyd without root privileges to remove it on exit
+* Disable sub-second polling intervals for distant NTP sources
+* Extend range of supported sub-second polling intervals
+* Get/set IPv4 destination/source address of NTP packets on FreeBSD
+* Make burst options and command useful with short polling intervals
+* Modify auto_offline option to activate when sending request failed
+* Respond from interface that received NTP request if possible
+* Add onoffline command to switch between online and offline state
+ according to current system network configuration
+* Improve example NetworkManager dispatcher script
+
+Bug fixes
+---------
+* Avoid waiting in Linux getrandom system call
+* Fix PPS support on FreeBSD and NetBSD
+
+New in version 3.3
+==================
+
+Enhancements
+------------
+* Add burst option to server/pool directive
+* Add stratum and tai options to refclock directive
+* Add support for Nettle crypto library
+* Add workaround for missing kernel receive timestamps on Linux
+* Wait for late hardware transmit timestamps
+* Improve source selection with unreachable sources
+* Improve protection against replay attacks on symmetric mode
+* Allow PHC refclock to use socket in /var/run/chrony
+* Add shutdown command to stop chronyd
+* Simplify format of response to manual list command
+* Improve handling of unknown responses in chronyc
+
+Bug fixes
+---------
+* Respond to NTPv1 client requests with zero mode
+* Fix -x option to not require CAP_SYS_TIME under non-root user
+* Fix acquisitionport directive to work with privilege separation
+* Fix handling of socket errors on Linux to avoid high CPU usage
+* Fix chronyc to not get stuck in infinite loop after clock step
+
+New in version 3.2
+==================
+
+Enhancements
+------------
+* Improve stability with NTP sources and reference clocks
+* Improve stability with hardware timestamping
+* Improve support for NTP interleaved modes
+* Control frequency of system clock on macOS 10.13 and later
+* Set TAI-UTC offset of system clock with leapsectz directive
+* Minimise data in client requests to improve privacy
+* Allow transmit-only hardware timestamping
+* Add support for new timestamping options introduced in Linux 4.13
+* Add root delay, root dispersion and maximum error to tracking log
+* Add mindelay and asymmetry options to server/peer/pool directive
+* Add extpps option to PHC refclock to timestamp external PPS signal
+* Add pps option to refclock directive to treat any refclock as PPS
+* Add width option to refclock directive to filter wrong pulse edges
+* Add rxfilter option to hwtimestamp directive
+* Add -x option to disable control of system clock
+* Add -l option to log to specified file instead of syslog
+* Allow multiple command-line options to be specified together
+* Allow starting without root privileges with -Q option
+* Update seccomp filter for new glibc versions
+* Dump history on exit by default with dumpdir directive
+* Use hardening compiler options by default
+
+Bug fixes
+---------
+* Don't drop PHC samples with low-resolution system clock
+* Ignore outliers in PHC tracking, RTC tracking, manual input
+* Increase polling interval when peer is not responding
+* Exit with error message when include directive fails
+* Don't allow slash after hostname in allow/deny directive/command
+* Try to connect to all addresses in chronyc before giving up
+
+New in version 3.1
+==================
+
+Enhancements
+------------
+* Add support for precise cross timestamping of PHC on Linux
+* Add minpoll, precision, nocrossts options to hwtimestamp directive
+* Add rawmeasurements option to log directive and modify measurements
+ option to log only valid measurements from synchronised sources
+* Allow sub-second polling interval with NTP sources
+
+Bug fixes
+---------
+* Fix time smoothing in interleaved mode
+
+New in version 3.0
+==================
+
+Enhancements
+------------
+* Add support for software and hardware timestamping on Linux
+* Add support for client/server and symmetric interleaved modes
+* Add support for MS-SNTP authentication in Samba
+* Add support for truncated MACs in NTPv4 packets
+* Estimate and correct for asymmetric network jitter
+* Increase default minsamples and polltarget to improve stability
+ with very low jitter
+* Add maxjitter directive to limit source selection by jitter
+* Add offset option to server/pool/peer directive
+* Add maxlockage option to refclock directive
+* Add -t option to chronyd to exit after specified time
+* Add partial protection against replay attacks on symmetric mode
+* Don't reset polling interval when switching sources to online state
+* Allow rate limiting with very short intervals
+* Improve maximum server throughput on Linux and NetBSD
+* Remove dump files after start
+* Add tab-completion to chronyc with libedit/readline
+* Add ntpdata command to print details about NTP measurements
+* Allow all source options to be set in add server/peer command
+* Indicate truncated addresses/hostnames in chronyc output
+* Print reference IDs as hexadecimal numbers to avoid confusion with
+ IPv4 addresses
+
+Bug fixes
+---------
+* Fix crash with disabled asynchronous name resolving
+
+New in version 2.4.1
+====================
+
+Bug fixes
+---------
+* Fix processing of kernel timestamps on non-Linux systems
+* Fix crash with smoothtime directive
+* Fix validation of refclock sample times
+* Fix parsing of refclock directive
+
+New in version 2.4
+==================
+
+Enhancements
+------------
+* Add orphan option to local directive for orphan mode compatible with ntpd
+* Add distance option to local directive to set activation threshold
+ (1 second by default)
+* Add maxdrift directive to set maximum allowed drift of system clock
+* Try to replace NTP sources exceeding maximum distance
+* Randomise source replacement to avoid getting stuck with bad sources
+* Randomise selection of sources from pools on start
+* Ignore reference timestamp as ntpd doesn't always set it correctly
+* Modify tracking report to use same values as seen by NTP clients
+* Add -c option to chronyc to write reports in CSV format
+* Provide detailed manual pages
+
+Bug fixes
+---------
+* Fix SOCK refclock to work correctly when not specified as last refclock
+* Fix initstepslew and -q/-Q options to accept time from own NTP clients
+* Fix authentication with keys using 512-bit hash functions
+* Fix crash on exit when multiple signals are received
+* Fix conversion of very small floating-point numbers in command packets
+
+Removed features
+----------------
+* Drop documentation in Texinfo format
+
+New in version 2.3
+==================
+
+Enhancements
+------------
+* Add support for NTP and command response rate limiting
+* Add support for dropping root privileges on Mac OS X, FreeBSD, Solaris
+* Add require and trust options for source selection
+* Enable logchange by default (1 second threshold)
+* Set RTC on Mac OS X with rtcsync directive
+* Allow binding to NTP port after dropping root privileges on NetBSD
+* Drop CAP_NET_BIND_SERVICE capability on Linux when NTP port is disabled
+* Resolve names in separate process when seccomp filter is enabled
+* Replace old records in client log when memory limit is reached
+* Don't reveal local time and synchronisation state in client packets
+* Don't keep client sockets open for longer than necessary
+* Ignore poll in KoD RATE packets as ntpd doesn't always set it correctly
+* Warn when using keys shorter than 80 bits
+* Add keygen command to generate random keys easily
+* Add serverstats command to report NTP and command packet statistics
+
+Bug fixes
+---------
+* Fix clock correction after making step on Mac OS X
+* Fix building on Solaris
+
+New in version 2.2.1
+====================
+
+Security fixes
+--------------
+* Restrict authentication of NTP server/peer to specified key (CVE-2016-1567)
+
+New in version 2.2
+==================
+
+Enhancements
+------------
+* Add support for configuration and monitoring over Unix domain socket
+ (accessible by root or chrony user when root privileges are dropped)
+* Add support for system call filtering with seccomp on Linux (experimental)
+* Add support for dropping root privileges on NetBSD
+* Control frequency of system clock on FreeBSD, NetBSD, Solaris
+* Add system leap second handling mode on FreeBSD, NetBSD, Solaris
+* Add dynamic drift removal on Mac OS X
+* Add support for setting real-time priority on Mac OS X
+* Add maxdistance directive to limit source selection by root distance
+ (3 seconds by default)
+* Add refresh command to get new addresses of NTP sources
+* Allow wildcard patterns in include directive
+* Restore time from driftfile with -s option if later than RTC time
+* Add configure option to set default hwclockfile
+* Add -d option to chronyc to enable debug messages
+* Allow multiple addresses to be specified for chronyc with -h option
+ and reconnect when no valid reply is received
+* Make check interval in waitsync command configurable
+
+Bug fixes
+---------
+* Fix building on NetBSD, Solaris
+* Restore time from driftfile with -s option if reading RTC failed
+
+Removed features
+----------------
+* Drop support for authentication with command key (run-time configuration
+ is now allowed only for local users that can access the Unix domain socket)
+
+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-1853)
+* Fix access configuration with subnet size indivisible by 4 (CVE-2015-1821)
+* Fix initialization of reply slots for authenticated commands (CVE-2015-1822)
+
+New in version 1.31
+===================
+
+Enhancements
+------------
+* Support operation in other NTP eras (next era begins in 2036),
+ NTP time is mapped to [-50, +86] years around build date by default
+* Restore time from driftfile with -s when RTC is missing/unsupported
+* Close connected client sockets when not waiting for reply
+* Use one client socket with random port when acquisitionport is 0
+* Use NTP packets instead of UDP echo for presend
+* Don't adjust polling interval when sending fails
+* Allow binding to addresses that don't exist yet
+* Ignore measurements around leap second
+* Improve detection of unexpected time jumps
+* Include example of logrotate configuration, systemd services and
+ NetworkManager dispatcher script
+
+Bug fixes
+---------
+* Reconnect client sockets for each request to follow changes
+ in network configuration automatically
+* Restart timer when polling interval is changed on reset
+
+New in version 1.30
+===================
+
+Enhancements
+------------
+* Add asynchronous name resolving with POSIX threads
+* Add PTP hardware clock (PHC) refclock driver
+* Add new generic clock driver to slew by adjusting frequency only
+ (without kernel PLL or adjtime) and use it on Linux
+* Add rtcautotrim directive to trim RTC automatically
+* Add hwclockfile directive to share RTC LOCAL/UTC setting with hwclock
+* Add maxslewrate directive to set maximum allowed slew rate
+* Add maxdispersion option for refclocks
+* Add -q/-Q options to set clock/print offset once and exit
+* Allow directives to be specified on chronyd command line
+* Replace frequency scaling in Linux driver with retaining of tick
+* Try to detect unexpected forward time jumps and reset state
+* Exit with non-zero code when maxchange limit is reached
+* Improve makestep to not start and stop slew unnecessarily
+* Change default corrtimeratio to 3.0 to improve frequency accuracy
+* Announce leap second only on last day of June and December
+* Use separate connected client sockets for each NTP server
+* Remove separate NTP implementation used for initstepslew
+* Limit maximum minpoll set by KoD RATE to default maxpoll
+* Don't send NTP requests with unknown key
+* Print warning when source is added with unknown key
+* Take leap second in PPS refclock from locked source
+* Make reading of RTC for initial trim more reliable
+* Don't create cmdmon sockets when cmdport is 0
+* Add configure option to set default user to drop root privileges
+* Add configure option to compile with debug messages
+* Print debug messages when -d is used more than once
+* Change format of messages written to terminal with -d
+* Write fatal messages also to stderr with -n
+* Use IP_RECVERR socket option in chronyc to not wait unnecessarily
+* Shorten default chronyc timeout for localhost
+* Change default hostname in chronyc from localhost to 127.0.0.1
+* Print error message on invalid syntax with all chronyc commands
+* Include simulation test suite using clknetsim
+
+Bug fixes
+---------
+* Fix crash when selecting with multiple preferred sources
+* Fix frequency calculation with large frequency offsets
+* Fix code writing drift and RTC files to compile correctly
+* Fix -4/-6 options in chronyc to not reset hostname set by -h
+* Fix refclock sample validation with sub-second polling interval
+* Set stratum correctly with non-PPS SOCK refclock and local stratum
+* Modify dispersion accounting in refclocks to prevent PPS getting
+ stuck with large dispersion and not accepting new samples
+
+New in version 1.29.1
+=====================
+
+Security fixes
+--------------
+* Modify chronyc protocol to prevent amplification attacks (CVE-2014-0021)
+ (incompatible with previous protocol version, chronyc supports both)
+
+New in version 1.29
+===================
+
+Security fixes
+--------------
+* Fix crash when processing crafted commands (CVE-2012-4502)
+ (possible with IP addresses allowed by cmdallow and localhost)
+* Don't send uninitialized data in SUBNETS_ACCESSED and CLIENT_ACCESSES
+ replies (CVE-2012-4503) (not used by chronyc)
+
+Other changes
+-------------
+* Drop support for SUBNETS_ACCESSED and CLIENT_ACCESSES commands
+
+New in version 1.28
+===================
+
+* Combine sources to improve accuracy
+* Make config and command parser strict
+* Add -a option to chronyc to authenticate automatically
+* Add -R option to ignore initstepslew and makestep directives
+* Add generatecommandkey, minsamples, maxsamples and user directives
+* Improve compatibility with NTPv1 and NTPv2 clients
+* Create sockets only in selected family with -4/-6 option
+* Treat address bind errors as non-fatal
+* Extend tracking log
+* Accept float values as initstepslew threshold
+* Allow hostnames in offline, online and burst commands
+* Fix and improve peer polling
+* Fix crash in config parsing with too many servers
+* Fix crash with duplicated initstepslew address
+* Fix delta calculation with extreme frequency offsets
+* Set local stratum correctly
+* Remove unnecessary adjtimex calls
+* Set paths in documentation by configure
+* Update chrony.spec
+
+New in version 1.27
+===================
+
+* Support for stronger keys via NSS or libtomcrypt library
+* Support reading leap second data from tz database
+* Support for precise clock stepping on Linux
+* Support for nanoseconds in SHM refclock
+* Make offset corrections smoother on Linux
+* Make transmit timestamps random below clock precision
+* Add corrtimeratio and maxchange directives
+* Extend tracking, sources and activity reports
+* Wait in foreground process until daemon is fully initialized
+* Fix crash with slow name resolving
+* Fix iburst with jittery sources
+* Fix offset stored in rtc data right after trimrtc
+* Fix crash and hang with RTC or manual samples
+* Don't use readonly adjtime on Linux kernels before 2.6.28
+* Changed chronyc protocol, incompatible with older versions
+
+New in version 1.26
+===================
+
+* Add compatibility with Linux 3.0 and later
+* Use proper source address in NTP replies on multihomed IPv6 hosts
+* Accept NTP packets with versions 4, 3 and 2
+* Cope with unexpected backward time jumps
+* Don't reset kernel frequency on start without drift file
+* Retry on permanent DNS error by default
+* Add waitsync command
+
+New in version 1.25
+===================
+
+* Improve accuracy with NTP sources
+* Improve accuracy with reference clocks
+* Improve polling interval adjustment
+* Improve stability with temporary asymmetric delays
+* Improve source selection
+* Improve initial synchronisation
+* Add delayed server name resolving
+* Add temperature compensation
+* Add nanosecond slewing to Linux driver
+* Add fallback drifts
+* Add iburst, minstratum, maxdelaydevratio, polltarget,
+ prefer, noselect options
+* Add rtcsync directive to enable Linux 11-minute mode
+* Add reselectdist, stratumweight, logbanner, maxclockerror,
+ include directives
+* Add -n option to not detach daemon from terminal
+* Fix pidfile directive
+* Fix name resolving with disabled IPv6 support
+* Fix reloading sample histories with reference clocks
+* Fix crash with auto_offline option
+* Fix online command on auto_offline sources
+* Fix file descriptor leaks
+* Increase burst polling interval and stop on KoD RATE
+* Set maxupdateskew to 1000 ppm by default
+* Require password for clients command
+* Update drift file at most once per hour
+* Use system headers for Linux RTC support
+* Reduce default chronyc timeout and make it configurable
+* Avoid large values in chronyc sources and sourcestats output
+* Add reselect command to force reselecting best source
+* Add -m option to allow multiple commands on command line
+
+New in version 1.24
+===================
+
+Security fixes
+--------------
+* Don't reply to invalid cmdmon packets (CVE-2010-0292)
+* Limit client log memory size (CVE-2010-0293)
+* Limit rate of syslog messages (CVE-2010-0294)
+
+Bug fixes/Enhancements
+----------------------
+* Support for reference clocks (SHM, SOCK, PPS drivers)
+* IPv6 support
+* Linux capabilities support (to drop root privileges)
+* Memory locking support on Linux
+* Real-time scheduler support on Linux
+* Leap second support on Linux
+* Support for editline library
+* Support for new Linux readonly adjtime
+* NTP client support for KoD RATE
+* Read kernel timestamps for received NTP packets
+* Reply to NTP requests with correct address on multihomed hosts
+* Retry name resolving after temporary failure
+* Fix makestep command, make it available on all systems
+* Add makestep directive for automatic clock stepping
+* Don't require _bigadj kernel symbol on NetBSD
+* Avoid blocking read in Linux RTC driver
+* Support for Linux on S/390 and PowerPC
+* Fix various bugs on 64-bit systems
+* Fix valgrind errors and compiler warnings
+* Improve configure to support common options and variables
+* Improve status checking and printing in chronyc
+* Return non-zero exit code on errors in chronyc
+* Reduce request timeout in chronyc
+* Print estimated offset in sourcestats
+* Changed chronyc protocol, incompatible with older versions
+
+New in version 1.23
+===================
+
+* Support for MIPS, x86_64, sparc, alpha, arm, FreeBSD
+* Fix serious sign-extension error in handling IP addresses
+* RTC support can be excluded at compile time
+* Make sources gcc-4 compatible
+* Fix various compiler warnings
+* Handle fluctuations in peer distance better.
+* Fixed handling of stratum zero.
+* Fix various problems for 64-bit systems
+* Flush chronyc output streams after each command, to allow it to be driven
+ through pipes
+* Manpage improvements
+
+Version 1.22
+============
+
+This release number was claimed by a release that Mandriva made to patch
+important bugs in 1.21. The official numbering has jumped to 1.23 as a
+consequence.
+
+New in version 1.21
+===================
+
+* Don't include Linux kernel header files any longer : allows chrony to compile
+ on recent distros.
+* Stop trying to use RTC if continuous streams of error messages would occur
+ (Linux with HPET).
+
+New in version 1.20
+===================
+
+* Many small tidy-ups and security improvements
+* Improve documentation (RTC support in post 2.0 kernels)
+* Remove trailing \n from syslog messages
+* Syslog messages now include IP and port number when packet cannot be sent.
+* Added the "acquisitionport" directive. (Kalle Olavi Niemitalo)
+* Use uname(2) instead of /proc/version to get kernel version.
+* Merge support for Linux on Alpha
+* Merge support for 64bit architectures
+* Don't link -lm if it's not needed
+* Fix Solaris build (broken by 64bit change)
+* Add detection of Linux 2.5
+* Allow arbitrary value of HZ in Linux kernel
+* Fix for chrony.spec on SuSE (Paul Elliot)
+* Fix handling of initstepslew if no servers are listed (John Hasler)
+* Fix install rule in Makefile if chronyd is in use (Juliusz Chroboczek)
+* Replace sprintf by snprintf to remove risk of buffer overrun (John Hasler)
+* Add --help to configure script
+
+New in version 1.19
+===================
+
+* Auto-detect kernel's timer interrupt rate (so-called 'HZ') when chronyd
+ starts instead of relying on compiled-in value.
+* Fix 2 bugs in function that creates the directory for the log and dump files.
+* Amended webpage URL and contact details.
+* Generate more informative syslog messages before exiting on failed
+ assertions.
+* Fix bugs in clamping code for the tick value used when slewing a large
+ offset.
+* Don't chown files to root during install (should be pointless, and makes RPM
+ building awkward as ordinary user.)
+* Include chrony.spec file for building RPMs
+
+New in version 1.18
+===================
+* Amend homepage and mailing list information to chrony.sunsite.dk
+* Delete pidfile on exit from chronyd.
+* Improvements to readline interface to chronyc
+* Only generate syslog message when synchronisation is initially lost (instead
+ of on every failed synchronisation attempt)
+* Use double fork approach when initialising daemon.
+* More things in contrib directory.
+* New options to help package builders: --infodir/--mandir for configure, and
+ DESTDIR=xxx for make. (See section 2.2 of chrony.txt for details).
+* Changed the wording of the messages generated by mailonchange and logchange
+ directives.
+
+New in version 1.17
+===================
+* Port to NetBSD
+* Configuration supports Linux on PPC
+* Fix compilation warnings
+* Several documentation improvements
+* Bundled manpages (taken from the 'missing manpages project')
+* Cope with lack of bzero function for Solaris 2.3 systems
+* Store chronyd's pid in a file (default /var/run/chronyd.pid) and check if
+ chronyd may already be running when starting up. New pidfile directive in
+ configuration file.
+* Any size subnet is now allowed in allow and deny commands. (Example:
+ 6.7.8/20 or 6.7.8.x/20 (any x) mean a 20 bit subnet).
+* The environment variables CC and CFLAGS passed to configure can now be used
+ to select the compiler and optimisation/debug options to use
+* Write syslog messages when chronyd loses synchronisation.
+* Print GPL text when chronyc is run.
+* Add NTP broadcast server capability (new broadcast directive).
+* Add 'auto_offline' option to server/peer (conf file) or add server/peer (via
+ chronyc).
+* Add 'activity' command to chronyc, to report how many servers/peers are
+ currently online/offline.
+* Fix long-standing bug with how the system time quantum was calculated.
+* Include support for systems with HZ!=100 (HZ is the timer interrupt
+ frequency).
+* Include example chrony.conf and chrony.keys files (examples subdirectory).
+* Include support for readline in chronyc.
+
+New in version 1.16.1
+=====================
+* Fix compilation problem on Linux 2.4.13 (spinlock.h / spinlock_t)
+
+New in version 1.16
+===================
+* More informative captions for 'sources' and 'sourcestats' commands in chronyc
+ (use 'sources -v' and 'sourcestats -v' to get them).
+* Correct behaviour for Solaris versions>=2.6 (dosynctodr not required on these
+ versions.)
+* Remove some compiler warnings (Solaris)
+* If last line of keys file doesn't have end-of-line, don't truncate final
+ character of that key.
+* Change timestamp format used in logfiles to make it fully numeric (to aid
+ importing data into spreadsheets etc)
+* Minor documentation updates and improvements.
+
+New in version 1.15
+===================
+* Add contributed change to 'configure' to support Solaris 2.8 on x86
+* Workaround for assertion failure that arises if two received packets occur
+ close together. (Still need to find out why this happens at all.)
+* Hopefully fix problem where fast slewing was incompatible with machines
+ that have a large background drift rate (=> tick value went out of range
+ for adjtimex() on Linux.)
+* Fix rtc_linux.c compile problems with 2.4.x kernel include files.
+* Include support for RTC device not being at /dev/rtc (new rtcdevice directive
+ in configuration file).
+* Include support for restricting network interfaces for commands (new
+ bindcmdaddress directive in configuration file)
+* Fix potential linking fault in pktlength.c (use of CROAK macro replaced by
+ normal assert).
+* Add some material on bug reporting + contributing to the chrony.texi file
+* Made the chrony.texi file "Vim6-friendly" (removed xrefs on @node lines,
+ added folding markers to chapters + sections.)
+* Switched over to GPL for the licence
+
+New in version 1.14
+===================
+* Fix compilation for certain other Linux distributions (including Mandrake
+ 7.1)
+
+New in version 1.13
+===================
+* Fixed compilation problems on Redhat/SuSE installations with recent 2.2.x
+ kernels.
+* Minor tidy-ups and documentation enhancements.
+* Add support for Linux 2.4 kernels
+
+New in version 1.12
+===================
+
+* Trial fix for long-standing bug in Linux RTC estimator when system time is
+ slewed.
+* Fix bug in chronyc if -h is specified without a hostname
+* Fixes to logging various error conditions when operating in daemon mode.
+* More stuff under contrib/
+* Changes to README file (e.g. about the new chrony-users mailing list)
+
+New in version 1.11a
+====================
+
+* Minor changes to contact details
+* Minor changes to installation details (chrony subdirectory under doc/)
+
+New in version 1.11
+===================
+
+* Improve robustness of installation procedure
+* Tidy up documenation and contact details
+* Distribute manual as .txt rather than as .ps
+* Add -n option to chronyc to work with numeric IP addresses rather than
+ names.
+* Add material in contrib subdirectory
+* Improve robustness of handling drift file and RTC coefficients file
+* Improve robustness of regression algorithm
+
+New in version 1.1
+==================
+
+Bug fixes
+---------
+
+* Made linear regression more resistant to rounding errors (old one
+ occasionally generated negative variances which made everything go
+ haywire). Trap infinite or 'not-a-number' values being used to
+ alter system clock to increase robustness further.
+
+Other changes/Enhancements
+--------------------------
+
+* Support for Linux 2.1 and 2.2 kernels
+
+* New command 'makestep' in chronyc to immediately jump the system
+ time to match the NTP estimated time (Linux only) - a response to
+ systems booting an hour wrong after summertime/wintertime changes,
+ due to RTCs running on local time. Needs extending to Sun driver
+ files too.
+
+* New directives 'logchange' and 'mailonchange' to log to syslog or
+ email to a specific address respectively if chronyd detects a clock
+ offset exceeding a defined threshold.
+
+* Added capability to log all client/peer NTP accesses and command
+ accesses (can be turned off with conf file directive 'noclientlog').
+ Added 'clients' command to chronyc to display this data.
+
+* Improved manual mode to use robust regression rather than 2 point
+ fit.
+
+* Added 'manual list' and 'manual delete' commands to chronyc to
+ allow display of entered timestamps and discretionary deletion of
+ outliers.
+
+* If host goes unsynchronised the dummy IP address 0.0.0.0 is detected
+ to avoid attempting a reverse name lookup (to stop dial on demand IP
+ links from being started)
+
+* Changed chronyc/chronyd protocol so messages are now all variable
+ length. Saves on network bandwidth particularly for large replies
+ from chronyd to chronyc (to support the clients command).
+
+* Added bindaddress directive to configuration file, to give
+ additional control over limiting which hosts can access the local
+ server.
+
+* Groundwork done for a port to Windows NT to compile with Cygwin
+ toolkit. chronyc works (to monitor another host). sys_winnt.c
+ needs finishing to use NT clock control API. Program structure
+ needs adapting to use Windows NT service functions, so it can be
+ started at boot time. Hopefully a Windows NT / Cygwin guru with
+ some spare time can take this port over :-)
+
+New in version 1.02
+===================
+
+Bug fixes
+---------
+
+* Fix error messages in chronyc if daemon is not reachable.
+
+* Fix config file problem for 'allow all' and 'deny all' without a
+ trailing machine address.
+
+* Remove fatal failed assertion if command socket cannot be read from
+ in daemon.
+
+* Rewrote timezone handling for Linux real time clock, following
+ various reported problems related to daylight saving.
+
+Other changes/Enhancements
+--------------------------
+
+* Configure script recognizes BSD/386 and uses SunOS 4.1 driver for
+ it.
+
+* Log files now print date as day-month-year rather than as a day
+ number. Milliseconds removed from timestamps of logged data.
+ Banners included in file to give meanings of columns.
+
+* Only do 1 initial step (followed by a trimming slew) when
+ initialising from RTC on Linux (previously did 2 steps).
+
+New in version 1.01
+===================
+
+Bug fixes
+---------
+
+* Handle timezone of RTC correctly with respect to daylight saving
+ time
+
+* Syntax check the chronyc 'local' command properly
+
+* Fixed assertion failed fault in median finder (used by RTC
+ regression fitting)
+
+Other changes/Enhancements
+--------------------------
+
+* Log selection of new NTP reference source to syslog.
+
+* Don't zero-pad IP address fields
+
+* Add new command to chronyc to allow logfiles to be cycled.
+
+* Extend allow/deny directive syntax in configuration file to so
+ directive can apply to all hosts on the Internet.
+
+* Tidy up printout of timestamps to make it clear they are in UTC
+
+* Make 'configure' check the processor type as well as the operating
+ system.
diff --git a/README b/README
new file mode 100644
index 0000000..aad727e
--- /dev/null
+++ b/README
@@ -0,0 +1,239 @@
+This is the README for chrony.
+
+What is chrony?
+===============
+
+chrony is a versatile implementation of the Network Time Protocol (NTP).
+It can synchronise 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 synchronised over the Internet is
+within a few milliseconds; on a LAN, accuracy is typically in tens of
+microseconds. With hardware timestamping, or a hardware reference clock,
+sub-microsecond accuracy may be 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?
+========================
+
+The software is known to work on Linux, FreeBSD, NetBSD, macOS 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?
+===================
+
+The file INSTALL gives instructions. On supported systems the
+compilation process should be automatic. You will need a C compiler,
+e.g. gcc or clang.
+
+What documentation is there?
+============================
+
+The distribution includes manual pages and a document containing
+Frequently Asked Questions (FAQ).
+
+The documentation is also available on the chrony web pages, accessible
+through the URL
+
+ https://chrony.tuxfamily.org/
+
+Where are new versions announced?
+=================================
+
+There is a low volume mailing list where new versions and other
+important news relating to chrony is announced. You can join this list
+by sending mail with the subject "subscribe" to
+
+chrony-announce-request@chrony.tuxfamily.org
+
+These messages will be copied to chrony-users (see below).
+
+How can I get support for chrony?
+and where can I discuss new features, possible bugs etc?
+========================================================
+
+There are 3 mailing lists relating to chrony. chrony-announce was
+mentioned above. chrony-users is a users' discussion list, e.g. for
+general questions and answers about using chrony. chrony-dev is a more
+technical list, e.g. for discussing how new features should be
+implemented, exchange of information between developers etc. To
+subscribe to either of these lists, send a message with the subject
+"subscribe" to
+
+chrony-users-request@chrony.tuxfamily.org
+or
+chrony-dev-request@chrony.tuxfamily.org
+
+as applicable.
+
+When you are reporting a bug, please send us all the information you can.
+Unfortunately, chrony has proven to be one of those programs where it is very
+difficult to reproduce bugs in a different environment. So we may have to
+interact with you quite a lot to obtain enough extra logging and tracing to
+pin-point the problem in some cases. Please be patient and plan for this!
+
+License
+=======
+
+chrony is distributed under the GNU General Public License version 2.
+
+Authors
+=======
+
+Richard P. Curnow <rc@rc0.org.uk>
+Miroslav Lichvar <mlichvar@redhat.com>
+
+Acknowledgements
+================
+
+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 the details of the protocol.
+
+The following people have provided patches and other major contributions
+to the program :
+
+Lonnie Abelbeck <lonnie@abelbeck.com>
+ Patch to add tab-completion to chronyc
+
+Benny Lyne Amorsen <benny@amorsen.dk>
+ Patch to add minstratum option
+
+Andrew Bishop <amb@gedanken.demon.co.uk>
+ Fixes for bugs in logging when in daemon mode
+ Fixes for compiler warnings
+ Robustness improvements for drift file
+ Improve installation (directory checking etc)
+ Entries in contrib directory
+ Improvements to 'sources' and 'sourcestats' output from chronyc
+ Improvements to documentation
+ Investigation of required dosynctodr behaviour for various Solaris
+ versions
+
+Stephan I. Boettcher <stephan@nevis1.columbia.edu>
+ Entries in contrib directory
+
+Erik Bryer <ebryer@spots.ab.ca>
+ Entries in contrib directory
+
+Bryan Christianson <bryan@whatroute.net>
+ Support for macOS
+ Support for privilege separation
+ Entries in contrib directory
+
+Juliusz Chroboczek <jch@pps.jussieu.fr>
+ Patch to fix install rule in Makefile if chronyd file is in use
+
+Christian Ehrhardt <christian.ehrhardt@canonical.com>
+ Patch to generate a warning message when CAP_SYS_TIME is missing
+
+Paul Elliott <pelliott@io.com>
+ Entries in contrib directory
+
+Mike Fleetwood <mike@rockover.demon.co.uk>
+ Fixes for compiler warnings
+
+Alexander Gretencord <arutha@gmx.de>
+ Changes to installation directory system to make it easier for
+ package builders
+
+Andrew Griffiths <agriffit@redhat.com>
+ Patch to add support for seccomp filter
+
+Walter Haidinger <walter.haidinger@gmx.at>
+ Access to a Linux installation where v1.12 wouldn't compile
+ Disc space for an independent backup of the sources
+
+Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
+ Port to NetBSD
+
+John Hasler <john@dhh.gt.org>
+ Project and website at tuxfamily.org
+ Changes to support 64 bit machines (i.e. those where
+ sizeof(unsigned long) > 4)
+ Bug fix to initstepslew directive
+ Fix to remove potential buffer overrun errors
+ Memory locking and real-time scheduler support
+ Fix fault where chronyd enters an endless loop
+
+Tjalling Hattink <t.hattink@fugro.nl>
+ Fix scheduler to allow stepping clock from timeout handler
+ Patch to take leap second in PPS refclock from locked source
+ Patch to make reading of RTC for initial trim more reliable
+
+Liam Hatton <me@liamhatton.com>
+ Advice on configuring for Linux on PPC
+
+Jachym Holecek <jakym@volny.cz>
+ Patch to make Linux real time clock work with devfs
+
+HÃ¥kan Johansson <f96hajo@chalmers.se>
+ Patch to avoid large values in sources and sourcestats output
+
+Jim Knoble <jmknoble@pobox.com>
+ Fixes for compiler warnings
+
+Antti Jrvinen <costello@iki.fi>
+ Advice on configuring for BSD/386
+
+Victor Moroz <vim@prv.adlum.ru>
+ Patch to support Linux with HZ!=100
+
+Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
+ Patch to add acquisitionport directive
+
+Frank Otto <sandwichmacher@web.de>
+ Handling arbitrary HZ values
+
+Denny Page <dennypage@me.com>
+ Advice on support for hardware timestamping
+
+Chris Perl <cperl@janestreet.com>
+ Patches to improve support for refclocks keeping time in TAI
+
+Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
+ Patch to add refresh command to chronyc
+
+Andreas Piesk <apiesk@virbus.de>
+ Patch to make chronyc use the readline library if available
+
+Andreas Steinmetz <ast@domdv.de>
+ Patch to make stratum of refclocks configurable
+
+Timo Teras <timo.teras@iki.fi>
+ Patch to reply correctly on multihomed hosts
+
+Bill Unruh <unruh@physics.ubc.ca>
+ Advice on statistics
+
+Stephen Wadeley <swadeley@redhat.com>
+ Improvements to man pages
+
+Wolfgang Weisselberg <weissel@netcologne.de>
+ Entries in contrib directory
+
+Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+ Many robustness and security improvements
+
+Ulrich Windl <ulrich.windl@rz.uni-regensburg.de> for the
+ Information about the Linux 2.2 kernel functionality compared to 2.0
+
+Doug Woodward <dougw@whistler.com>
+ Advice on configuring for Solaris 2.8 on x86
+
+Many other people have contributed bug reports and suggestions. We are sorry
+we cannot identify all of you individually.
diff --git a/addressing.h b/addressing.h
new file mode 100644
index 0000000..9ecc18b
--- /dev/null
+++ b/addressing.h
@@ -0,0 +1,62 @@
+/*
+ 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.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Types used for addressing sources etc
+ */
+
+#ifndef GOT_ADDRESSING_H
+#define GOT_ADDRESSING_H
+
+#include "sysincl.h"
+
+/* This type is used to represent an IPv4 address or IPv6 address.
+ All parts are in HOST order, NOT network order. */
+
+#define IPADDR_UNSPEC 0
+#define IPADDR_INET4 1
+#define IPADDR_INET6 2
+
+typedef struct {
+ union {
+ uint32_t in4;
+ uint8_t in6[16];
+ } addr;
+ uint16_t family;
+ uint16_t _pad;
+} IPAddr;
+
+typedef struct {
+ IPAddr ip_addr;
+ unsigned short port;
+} NTP_Remote_Address;
+
+#define INVALID_IF_INDEX -1
+
+typedef struct {
+ IPAddr ip_addr;
+ int if_index;
+ int sock_fd;
+} NTP_Local_Address;
+
+#endif /* GOT_ADDRESSING_H */
+
diff --git a/addrfilt.c b/addrfilt.c
new file mode 100644
index 0000000..dd16700
--- /dev/null
+++ b/addrfilt.c
@@ -0,0 +1,403 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow 1997,1998,1999,2000,2001,2002,2005
+ * 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
+ * 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 provides a set of routines for checking IP addresses
+ against a set of rules and deciding whether they are allowed or
+ disallowed.
+
+ */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "addrfilt.h"
+#include "memory.h"
+
+/* Define the number of bits which are stripped off per level of
+ indirection in the tables */
+#define NBITS 4
+
+/* Define the table size */
+#define TABLE_SIZE (1UL<<NBITS)
+
+typedef enum {DENY, ALLOW, AS_PARENT} State;
+
+typedef struct _TableNode {
+ State state;
+ struct _TableNode *extended;
+} TableNode;
+
+struct ADF_AuthTableInst {
+ TableNode base4; /* IPv4 node */
+ TableNode base6; /* IPv6 node */
+};
+
+/* ================================================== */
+
+static void
+split_ip6(IPAddr *ip, uint32_t *dst)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ dst[i] = (uint32_t)ip->addr.in6[i * 4 + 0] << 24 |
+ ip->addr.in6[i * 4 + 1] << 16 |
+ ip->addr.in6[i * 4 + 2] << 8 |
+ ip->addr.in6[i * 4 + 3];
+}
+
+/* ================================================== */
+
+inline static uint32_t
+get_subnet(uint32_t *addr, unsigned int where)
+{
+ int off;
+
+ off = where / 32;
+ where %= 32;
+
+ return (addr[off] >> (32 - NBITS - where)) & ((1UL << NBITS) - 1);
+}
+
+/* ================================================== */
+
+ADF_AuthTable
+ADF_CreateTable(void)
+{
+ ADF_AuthTable result;
+ result = MallocNew(struct ADF_AuthTableInst);
+
+ /* Default is that nothing is allowed */
+ result->base4.state = DENY;
+ result->base4.extended = NULL;
+ result->base6.state = DENY;
+ result->base6.extended = NULL;
+
+ return result;
+}
+
+/* ================================================== */
+/* This function deletes all definitions of child nodes, in effect
+ pruning a whole subnet definition back to a single parent
+ record. */
+static void
+close_node(TableNode *node)
+{
+ int i;
+ TableNode *child_node;
+
+ if (node->extended != NULL) {
+ for (i=0; i<TABLE_SIZE; i++) {
+ child_node = &(node->extended[i]);
+ close_node(child_node);
+ }
+ Free(node->extended);
+ node->extended = NULL;
+ }
+}
+
+
+/* ================================================== */
+/* Allocate the extension field in a node, and set all the children's
+ states to default to that of the node being extended */
+
+static void
+open_node(TableNode *node)
+{
+ int i;
+ TableNode *child_node;
+
+ if (node->extended == NULL) {
+
+ node->extended = MallocArray(struct _TableNode, TABLE_SIZE);
+
+ for (i=0; i<TABLE_SIZE; i++) {
+ child_node = &(node->extended[i]);
+ child_node->state = AS_PARENT;
+ child_node->extended = NULL;
+ }
+ }
+}
+
+/* ================================================== */
+
+static ADF_Status
+set_subnet(TableNode *start_node,
+ uint32_t *ip,
+ int ip_len,
+ int subnet_bits,
+ State new_state,
+ int delete_children)
+{
+ int bits_to_go, bits_consumed;
+ uint32_t subnet;
+ TableNode *node;
+
+ bits_consumed = 0;
+ bits_to_go = subnet_bits;
+ node = start_node;
+
+ if ((subnet_bits < 0) ||
+ (subnet_bits > 32 * ip_len)) {
+
+ return ADF_BADSUBNET;
+
+ } else {
+
+ if ((bits_to_go & (NBITS-1)) == 0) {
+
+ while (bits_to_go > 0) {
+ subnet = get_subnet(ip, bits_consumed);
+ if (!(node->extended)) {
+ open_node(node);
+ }
+ node = &(node->extended[subnet]);
+ bits_to_go -= NBITS;
+ bits_consumed += NBITS;
+ }
+
+ if (delete_children) {
+ close_node(node);
+ }
+ node->state = new_state;
+
+ } else { /* Have to set multiple entries */
+ int N, i, j;
+ TableNode *this_node;
+
+ while (bits_to_go >= NBITS) {
+ subnet = get_subnet(ip, bits_consumed);
+ if (!(node->extended)) {
+ open_node(node);
+ }
+ node = &(node->extended[subnet]);
+ bits_to_go -= NBITS;
+ bits_consumed += NBITS;
+ }
+
+ /* How many subnet entries to set : 1->8, 2->4, 3->2 */
+ N = 1 << (NBITS-bits_to_go);
+
+ subnet = get_subnet(ip, bits_consumed) & ~(N - 1);
+ assert(subnet + N <= TABLE_SIZE);
+
+ if (!(node->extended)) {
+ open_node(node);
+ }
+
+ for (i=subnet, j=0; j<N; i++, j++) {
+ this_node = &(node->extended[i]);
+ if (delete_children) {
+ close_node(this_node);
+ }
+ this_node->state = new_state;
+ }
+ }
+
+ return ADF_SUCCESS;
+ }
+
+}
+
+/* ================================================== */
+
+static ADF_Status
+set_subnet_(ADF_AuthTable table,
+ IPAddr *ip_addr,
+ int subnet_bits,
+ State new_state,
+ int delete_children)
+{
+ uint32_t ip6[4];
+
+ switch (ip_addr->family) {
+ case IPADDR_INET4:
+ return set_subnet(&table->base4, &ip_addr->addr.in4, 1, subnet_bits, new_state, delete_children);
+ case IPADDR_INET6:
+ split_ip6(ip_addr, ip6);
+ return set_subnet(&table->base6, ip6, 4, subnet_bits, new_state, delete_children);
+ case IPADDR_UNSPEC:
+ /* Apply to both, subnet_bits has to be 0 */
+ if (subnet_bits != 0)
+ return ADF_BADSUBNET;
+ memset(ip6, 0, sizeof (ip6));
+ if (set_subnet(&table->base4, ip6, 1, 0, new_state, delete_children) == ADF_SUCCESS &&
+ set_subnet(&table->base6, ip6, 4, 0, new_state, delete_children) == ADF_SUCCESS)
+ return ADF_SUCCESS;
+ break;
+ }
+
+ return ADF_BADSUBNET;
+}
+
+ADF_Status
+ADF_Allow(ADF_AuthTable table,
+ IPAddr *ip,
+ int subnet_bits)
+{
+ return set_subnet_(table, ip, subnet_bits, ALLOW, 0);
+}
+
+/* ================================================== */
+
+
+ADF_Status
+ADF_AllowAll(ADF_AuthTable table,
+ IPAddr *ip,
+ int subnet_bits)
+{
+ return set_subnet_(table, ip, subnet_bits, ALLOW, 1);
+}
+
+/* ================================================== */
+
+ADF_Status
+ADF_Deny(ADF_AuthTable table,
+ IPAddr *ip,
+ int subnet_bits)
+{
+ return set_subnet_(table, ip, subnet_bits, DENY, 0);
+}
+
+/* ================================================== */
+
+ADF_Status
+ADF_DenyAll(ADF_AuthTable table,
+ IPAddr *ip,
+ int subnet_bits)
+{
+ return set_subnet_(table, ip, subnet_bits, DENY, 1);
+}
+
+/* ================================================== */
+
+void
+ADF_DestroyTable(ADF_AuthTable table)
+{
+ close_node(&table->base4);
+ close_node(&table->base6);
+ Free(table);
+}
+
+/* ================================================== */
+
+static int
+check_ip_in_node(TableNode *start_node, uint32_t *ip)
+{
+ uint32_t subnet;
+ int bits_consumed = 0;
+ int result = 0;
+ int finished = 0;
+ TableNode *node;
+ State state=DENY;
+
+ node = start_node;
+
+ do {
+ if (node->state != AS_PARENT) {
+ state = node->state;
+ }
+ if (node->extended) {
+ subnet = get_subnet(ip, bits_consumed);
+ node = &(node->extended[subnet]);
+ bits_consumed += NBITS;
+ } else {
+ /* Make decision on this node */
+ finished = 1;
+ }
+ } while (!finished);
+
+ switch (state) {
+ case ALLOW:
+ result = 1;
+ break;
+ case DENY:
+ result = 0;
+ break;
+ case AS_PARENT:
+ assert(0);
+ break;
+ }
+
+ return result;
+}
+
+
+/* ================================================== */
+
+int
+ADF_IsAllowed(ADF_AuthTable table,
+ IPAddr *ip_addr)
+{
+ uint32_t ip6[4];
+
+ switch (ip_addr->family) {
+ case IPADDR_INET4:
+ return check_ip_in_node(&table->base4, &ip_addr->addr.in4);
+ case IPADDR_INET6:
+ split_ip6(ip_addr, ip6);
+ return check_ip_in_node(&table->base6, ip6);
+ }
+
+ return 0;
+}
+
+/* ================================================== */
+
+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;
+ }
+}
diff --git a/addrfilt.h b/addrfilt.h
new file mode 100644
index 0000000..b8c131f
--- /dev/null
+++ b/addrfilt.h
@@ -0,0 +1,80 @@
+/*
+ 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.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Module for providing an authorisation filter on IP addresses
+ */
+
+#ifndef GOT_ADDRFILT_H
+#define GOT_ADDRFILT_H
+
+#include "addressing.h"
+
+typedef struct ADF_AuthTableInst *ADF_AuthTable;
+
+typedef enum {
+ ADF_SUCCESS,
+ ADF_BADSUBNET
+} ADF_Status;
+
+
+/* Create a new table. The default rule is deny for everything */
+extern ADF_AuthTable ADF_CreateTable(void);
+
+/* Allow anything in the supplied subnet, EXCEPT for any more specific
+ subnets that are already defined */
+extern ADF_Status ADF_Allow(ADF_AuthTable table,
+ IPAddr *ip,
+ int subnet_bits);
+
+/* Allow anything in the supplied subnet, overwriting existing
+ definitions for any more specific subnets */
+extern ADF_Status ADF_AllowAll(ADF_AuthTable table,
+ IPAddr *ip,
+ int subnet_bits);
+
+/* Deny anything in the supplied subnet, EXCEPT for any more specific
+ subnets that are already defined */
+extern ADF_Status ADF_Deny(ADF_AuthTable table,
+ IPAddr *ip,
+ int subnet_bits);
+
+/* Deny anything in the supplied subnet, overwriting existing
+ definitions for any more specific subnets */
+extern ADF_Status ADF_DenyAll(ADF_AuthTable table,
+ IPAddr *ip,
+ int subnet_bits);
+
+/* Clear up the table */
+extern void ADF_DestroyTable(ADF_AuthTable table);
+
+/* Check whether a given IP address is allowed by the rules in
+ the 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..d70cff9
--- /dev/null
+++ b/array.c
@@ -0,0 +1,130 @@
+/*
+ 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)
+{
+ 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;
+ }
+
+ array->data = Realloc2(array->data, array->allocated, array->elem_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 a non-NULL pointer when the array has zero size */
+ if (!array->data) {
+ assert(!array->used);
+ return 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/candm.h b/candm.h
new file mode 100644
index 0000000..cb79739
--- /dev/null
+++ b/candm.h
@@ -0,0 +1,726 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow 1997-2003
+ *
+ * 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.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Definitions for the network protocol used for command and monitoring
+ of the timeserver.
+
+ */
+
+#ifndef GOT_CANDM_H
+#define GOT_CANDM_H
+
+#include "sysincl.h"
+#include "addressing.h"
+
+/* This is the default port to use for CANDM, if no alternative is
+ defined */
+#define DEFAULT_CANDM_PORT 323
+
+/* Request codes */
+#define REQ_NULL 0
+#define REQ_ONLINE 1
+#define REQ_OFFLINE 2
+#define REQ_BURST 3
+#define REQ_MODIFY_MINPOLL 4
+#define REQ_MODIFY_MAXPOLL 5
+#define REQ_DUMP 6
+#define REQ_MODIFY_MAXDELAY 7
+#define REQ_MODIFY_MAXDELAYRATIO 8
+#define REQ_MODIFY_MAXUPDATESKEW 9
+#define REQ_LOGON 10
+#define REQ_SETTIME 11
+#define REQ_LOCAL 12
+#define REQ_MANUAL 13
+#define REQ_N_SOURCES 14
+#define REQ_SOURCE_DATA 15
+#define REQ_REKEY 16
+#define REQ_ALLOW 17
+#define REQ_ALLOWALL 18
+#define REQ_DENY 19
+#define REQ_DENYALL 20
+#define REQ_CMDALLOW 21
+#define REQ_CMDALLOWALL 22
+#define REQ_CMDDENY 23
+#define REQ_CMDDENYALL 24
+#define REQ_ACCHECK 25
+#define REQ_CMDACCHECK 26
+#define REQ_ADD_SERVER 27
+#define REQ_ADD_PEER 28
+#define REQ_DEL_SOURCE 29
+#define REQ_WRITERTC 30
+#define REQ_DFREQ 31
+#define REQ_DOFFSET 32
+#define REQ_TRACKING 33
+#define REQ_SOURCESTATS 34
+#define REQ_RTCREPORT 35
+#define REQ_TRIMRTC 36
+#define REQ_CYCLELOGS 37
+#define REQ_SUBNETS_ACCESSED 38
+#define REQ_CLIENT_ACCESSES 39
+#define REQ_CLIENT_ACCESSES_BY_INDEX 40
+#define REQ_MANUAL_LIST 41
+#define REQ_MANUAL_DELETE 42
+#define REQ_MAKESTEP 43
+#define REQ_ACTIVITY 44
+#define REQ_MODIFY_MINSTRATUM 45
+#define REQ_MODIFY_POLLTARGET 46
+#define REQ_MODIFY_MAXDELAYDEVRATIO 47
+#define REQ_RESELECT 48
+#define REQ_RESELECTDISTANCE 49
+#define REQ_MODIFY_MAKESTEP 50
+#define REQ_SMOOTHING 51
+#define REQ_SMOOTHTIME 52
+#define REQ_REFRESH 53
+#define REQ_SERVER_STATS 54
+#define REQ_CLIENT_ACCESSES_BY_INDEX2 55
+#define REQ_LOCAL2 56
+#define REQ_NTP_DATA 57
+#define REQ_ADD_SERVER2 58
+#define REQ_ADD_PEER2 59
+#define REQ_ADD_SERVER3 60
+#define REQ_ADD_PEER3 61
+#define REQ_SHUTDOWN 62
+#define REQ_ONOFFLINE 63
+#define N_REQUEST_TYPES 64
+
+/* Structure used to exchange timespecs independent of time_t size */
+typedef struct {
+ uint32_t tv_sec_high;
+ uint32_t tv_sec_low;
+ uint32_t tv_nsec;
+} Timespec;
+
+/* This is used in tv_sec_high for 32-bit timestamps */
+#define TV_NOHIGHSEC 0x7fffffff
+
+/* 32-bit floating-point format consisting of 7-bit signed exponent
+ and 25-bit signed coefficient without hidden bit.
+ The result is calculated as: 2^(exp - 25) * coef */
+typedef struct {
+ int32_t f;
+} Float;
+
+/* The EOR (end of record) fields are used by the offsetof operator in
+ pktlength.c, to get the number of bytes that ought to be
+ transmitted for each packet type. */
+
+typedef struct {
+ int32_t EOR;
+} REQ_Null;
+
+typedef struct {
+ IPAddr mask;
+ IPAddr address;
+ int32_t EOR;
+} REQ_Online;
+
+typedef struct {
+ IPAddr mask;
+ IPAddr address;
+ int32_t EOR;
+} REQ_Offline;
+
+typedef struct {
+ IPAddr mask;
+ IPAddr address;
+ int32_t n_good_samples;
+ int32_t n_total_samples;
+ int32_t EOR;
+} REQ_Burst;
+
+typedef struct {
+ IPAddr address;
+ int32_t new_minpoll;
+ int32_t EOR;
+} REQ_Modify_Minpoll;
+
+typedef struct {
+ IPAddr address;
+ int32_t new_maxpoll;
+ int32_t EOR;
+} REQ_Modify_Maxpoll;
+
+typedef struct {
+ int32_t pad;
+ int32_t EOR;
+} REQ_Dump;
+
+typedef struct {
+ IPAddr address;
+ Float new_max_delay;
+ int32_t EOR;
+} REQ_Modify_Maxdelay;
+
+typedef struct {
+ IPAddr address;
+ Float new_max_delay_ratio;
+ int32_t EOR;
+} REQ_Modify_Maxdelayratio;
+
+typedef struct {
+ IPAddr address;
+ Float new_max_delay_dev_ratio;
+ int32_t EOR;
+} REQ_Modify_Maxdelaydevratio;
+
+typedef struct {
+ IPAddr address;
+ int32_t new_min_stratum;
+ int32_t EOR;
+} REQ_Modify_Minstratum;
+
+typedef struct {
+ IPAddr address;
+ int32_t new_poll_target;
+ int32_t EOR;
+} REQ_Modify_Polltarget;
+
+typedef struct {
+ Float new_max_update_skew;
+ int32_t EOR;
+} REQ_Modify_Maxupdateskew;
+
+typedef struct {
+ int32_t limit;
+ Float threshold;
+ int32_t EOR;
+} REQ_Modify_Makestep;
+
+typedef struct {
+ Timespec ts;
+ int32_t EOR;
+} REQ_Logon;
+
+typedef struct {
+ Timespec ts;
+ int32_t EOR;
+} REQ_Settime;
+
+typedef struct {
+ int32_t on_off;
+ int32_t stratum;
+ Float distance;
+ int32_t orphan;
+ int32_t EOR;
+} REQ_Local;
+
+typedef struct {
+ int32_t option;
+ int32_t EOR;
+} REQ_Manual;
+
+typedef struct {
+ int32_t index;
+ int32_t EOR;
+} REQ_Source_Data;
+
+typedef struct {
+ IPAddr ip;
+ int32_t subnet_bits;
+ int32_t EOR;
+} REQ_Allow_Deny;
+
+typedef struct {
+ IPAddr ip;
+ int32_t EOR;
+} REQ_Ac_Check;
+
+/* Flags used in NTP source requests */
+#define REQ_ADDSRC_ONLINE 0x1
+#define REQ_ADDSRC_AUTOOFFLINE 0x2
+#define REQ_ADDSRC_IBURST 0x4
+#define REQ_ADDSRC_PREFER 0x8
+#define REQ_ADDSRC_NOSELECT 0x10
+#define REQ_ADDSRC_TRUST 0x20
+#define REQ_ADDSRC_REQUIRE 0x40
+#define REQ_ADDSRC_INTERLEAVED 0x80
+#define REQ_ADDSRC_BURST 0x100
+
+typedef struct {
+ IPAddr ip_addr;
+ uint32_t port;
+ int32_t minpoll;
+ int32_t maxpoll;
+ int32_t presend_minpoll;
+ uint32_t min_stratum;
+ uint32_t poll_target;
+ uint32_t version;
+ uint32_t max_sources;
+ int32_t min_samples;
+ int32_t max_samples;
+ uint32_t authkey;
+ Float max_delay;
+ Float max_delay_ratio;
+ Float max_delay_dev_ratio;
+ Float min_delay;
+ Float asymmetry;
+ Float offset;
+ uint32_t flags;
+ int32_t filter_length;
+ uint32_t reserved[3];
+ int32_t EOR;
+} REQ_NTP_Source;
+
+typedef struct {
+ IPAddr ip_addr;
+ int32_t EOR;
+} REQ_Del_Source;
+
+typedef struct {
+ Float dfreq;
+ int32_t EOR;
+} REQ_Dfreq;
+
+typedef struct {
+ int32_t sec;
+ int32_t usec;
+ int32_t EOR;
+} REQ_Doffset;
+
+typedef struct {
+ uint32_t index;
+ int32_t EOR;
+} REQ_Sourcestats;
+
+/* This is based on the response size rather than the
+ request size */
+#define MAX_CLIENT_ACCESSES 8
+
+typedef struct {
+ uint32_t first_index;
+ uint32_t n_clients;
+ int32_t EOR;
+} REQ_ClientAccessesByIndex;
+
+typedef struct {
+ int32_t index;
+ int32_t EOR;
+} REQ_ManualDelete;
+
+typedef struct {
+ Float distance;
+ int32_t EOR;
+} REQ_ReselectDistance;
+
+#define REQ_SMOOTHTIME_RESET 0
+#define REQ_SMOOTHTIME_ACTIVATE 1
+
+typedef struct {
+ int32_t option;
+ int32_t EOR;
+} REQ_SmoothTime;
+
+typedef struct {
+ IPAddr ip_addr;
+ int32_t EOR;
+} REQ_NTPData;
+
+/* ================================================== */
+
+#define PKT_TYPE_CMD_REQUEST 1
+#define PKT_TYPE_CMD_REPLY 2
+
+/* This version number needs to be incremented whenever the packet
+ size and/or the format of any of the existing messages is changed.
+ Other changes, e.g. new command types, should be handled cleanly by
+ client.c and cmdmon.c anyway, so the version can stay the same.
+
+ Version 1 : original version with fixed size packets
+
+ Version 2 : both command and reply packet sizes made capable of
+ being variable length.
+
+ Version 3 : NTP_Source message lengthened (auto_offline)
+
+ Version 4 : IPv6 addressing added, 64-bit time values, sourcestats
+ and tracking reports extended, added flags to NTP source request,
+ trimmed source report, replaced fixed-point format with floating-point
+ and used also instead of integer microseconds, new commands: modify stratum,
+ modify polltarget, modify maxdelaydevratio, reselect, reselectdistance
+
+ Version 5 : auth data moved to the end of the packet to allow hashes with
+ different sizes, extended sources, tracking and activity reports, dropped
+ subnets accessed and client accesses
+
+ Version 6 : added padding to requests to prevent amplification attack,
+ changed maximum number of samples in manual list to 16, new commands: modify
+ makestep, smoothing, smoothtime
+
+ Support for authentication was removed later in version 6 of the protocol
+ and commands that required authentication are allowed only locally over Unix
+ domain socket.
+
+ Version 6 (no authentication) : changed format of client accesses by index
+ (using new request/reply types) and manual timestamp, added new fields and
+ flags to NTP source request and report, made length of manual list constant,
+ added new commands: ntpdata, refresh, serverstats, shutdown
+ */
+
+#define PROTO_VERSION_NUMBER 6
+
+/* The oldest protocol versions that are compatible enough with the current
+ version to report a version mismatch for the server and the client */
+#define PROTO_VERSION_MISMATCH_COMPAT_SERVER 5
+#define PROTO_VERSION_MISMATCH_COMPAT_CLIENT 4
+
+/* The first protocol version using padding in requests */
+#define PROTO_VERSION_PADDING 6
+
+/* The maximum length of padding in request packet, currently
+ defined by MANUAL_LIST */
+#define MAX_PADDING_LENGTH 396
+
+/* ================================================== */
+
+typedef struct {
+ uint8_t version; /* Protocol version */
+ uint8_t pkt_type; /* What sort of packet this is */
+ uint8_t res1;
+ uint8_t res2;
+ uint16_t command; /* Which command is being issued */
+ uint16_t attempt; /* How many resends the client has done
+ (count up from zero for same sequence
+ number) */
+ uint32_t sequence; /* Client's sequence number */
+ uint32_t pad1;
+ uint32_t pad2;
+
+ union {
+ REQ_Null null;
+ REQ_Online online;
+ REQ_Offline offline;
+ REQ_Burst burst;
+ REQ_Modify_Minpoll modify_minpoll;
+ REQ_Modify_Maxpoll modify_maxpoll;
+ REQ_Dump dump;
+ REQ_Modify_Maxdelay modify_maxdelay;
+ REQ_Modify_Maxdelayratio modify_maxdelayratio;
+ REQ_Modify_Maxdelaydevratio modify_maxdelaydevratio;
+ 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_Source_Data source_data;
+ REQ_Allow_Deny allow_deny;
+ REQ_Ac_Check ac_check;
+ REQ_NTP_Source ntp_source;
+ REQ_Del_Source del_source;
+ REQ_Dfreq dfreq;
+ REQ_Doffset doffset;
+ REQ_Sourcestats sourcestats;
+ REQ_ClientAccessesByIndex client_accesses_by_index;
+ REQ_ManualDelete manual_delete;
+ REQ_ReselectDistance reselect_distance;
+ REQ_SmoothTime smoothtime;
+ REQ_NTPData ntp_data;
+ } data; /* Command specific parameters */
+
+ /* Padding used to prevent traffic amplification. It only defines the
+ maximum size of the packet, there is no hole after the data field. */
+ uint8_t padding[MAX_PADDING_LENGTH];
+
+} CMD_Request;
+
+/* ================================================== */
+/* Authority codes for command types */
+
+#define PERMIT_OPEN 0
+#define PERMIT_LOCAL 1
+#define PERMIT_AUTH 2
+
+/* ================================================== */
+
+/* Reply codes */
+#define RPY_NULL 1
+#define RPY_N_SOURCES 2
+#define RPY_SOURCE_DATA 3
+#define RPY_MANUAL_TIMESTAMP 4
+#define RPY_TRACKING 5
+#define RPY_SOURCESTATS 6
+#define RPY_RTC 7
+#define RPY_SUBNETS_ACCESSED 8
+#define RPY_CLIENT_ACCESSES 9
+#define RPY_CLIENT_ACCESSES_BY_INDEX 10
+#define RPY_MANUAL_LIST 11
+#define RPY_ACTIVITY 12
+#define RPY_SMOOTHING 13
+#define RPY_SERVER_STATS 14
+#define RPY_CLIENT_ACCESSES_BY_INDEX2 15
+#define RPY_NTP_DATA 16
+#define RPY_MANUAL_TIMESTAMP2 17
+#define RPY_MANUAL_LIST2 18
+#define N_REPLY_TYPES 19
+
+/* Status codes */
+#define STT_SUCCESS 0
+#define STT_FAILED 1
+#define STT_UNAUTH 2
+#define STT_INVALID 3
+#define STT_NOSUCHSOURCE 4
+#define STT_INVALIDTS 5
+#define STT_NOTENABLED 6
+#define STT_BADSUBNET 7
+#define STT_ACCESSALLOWED 8
+#define STT_ACCESSDENIED 9
+/* Deprecated */
+#define STT_NOHOSTACCESS 10
+#define STT_SOURCEALREADYKNOWN 11
+#define STT_TOOMANYSOURCES 12
+#define STT_NORTC 13
+#define STT_BADRTCFILE 14
+#define STT_INACTIVE 15
+#define STT_BADSAMPLE 16
+#define STT_INVALIDAF 17
+#define STT_BADPKTVERSION 18
+#define STT_BADPKTLENGTH 19
+
+typedef struct {
+ int32_t EOR;
+} RPY_Null;
+
+typedef struct {
+ uint32_t n_sources;
+ int32_t EOR;
+} RPY_N_Sources;
+
+#define RPY_SD_MD_CLIENT 0
+#define RPY_SD_MD_PEER 1
+#define RPY_SD_MD_REF 2
+
+#define RPY_SD_ST_SYNC 0
+#define RPY_SD_ST_UNREACH 1
+#define RPY_SD_ST_FALSETICKER 2
+#define RPY_SD_ST_JITTERY 3
+#define RPY_SD_ST_CANDIDATE 4
+#define RPY_SD_ST_OUTLIER 5
+
+#define RPY_SD_FLAG_NOSELECT 0x1
+#define RPY_SD_FLAG_PREFER 0x2
+#define RPY_SD_FLAG_TRUST 0x4
+#define RPY_SD_FLAG_REQUIRE 0x8
+
+typedef struct {
+ IPAddr ip_addr;
+ int16_t poll;
+ uint16_t stratum;
+ uint16_t state;
+ uint16_t mode;
+ uint16_t flags;
+ uint16_t reachability;
+ uint32_t since_sample;
+ Float orig_latest_meas;
+ Float latest_meas;
+ Float latest_meas_err;
+ int32_t EOR;
+} RPY_Source_Data;
+
+typedef struct {
+ uint32_t ref_id;
+ IPAddr ip_addr;
+ uint16_t stratum;
+ uint16_t leap_status;
+ Timespec ref_time;
+ Float current_correction;
+ Float last_offset;
+ Float rms_offset;
+ Float freq_ppm;
+ Float resid_freq_ppm;
+ Float skew_ppm;
+ Float root_delay;
+ Float root_dispersion;
+ Float last_update_interval;
+ int32_t EOR;
+} RPY_Tracking;
+
+typedef struct {
+ uint32_t ref_id;
+ IPAddr ip_addr;
+ uint32_t n_samples;
+ uint32_t n_runs;
+ uint32_t span_seconds;
+ Float sd;
+ Float resid_freq_ppm;
+ Float skew_ppm;
+ Float est_offset;
+ Float est_offset_err;
+ int32_t EOR;
+} RPY_Sourcestats;
+
+typedef struct {
+ Timespec ref_time;
+ uint16_t n_samples;
+ uint16_t n_runs;
+ uint32_t span_seconds;
+ Float rtc_seconds_fast;
+ Float rtc_gain_rate_ppm;
+ int32_t EOR;
+} RPY_Rtc;
+
+typedef struct {
+ Float offset;
+ Float dfreq_ppm;
+ Float new_afreq_ppm;
+ int32_t EOR;
+} RPY_ManualTimestamp;
+
+typedef struct {
+ IPAddr ip;
+ uint32_t ntp_hits;
+ uint32_t cmd_hits;
+ uint32_t ntp_drops;
+ uint32_t cmd_drops;
+ int8_t ntp_interval;
+ int8_t cmd_interval;
+ int8_t ntp_timeout_interval;
+ int8_t pad;
+ uint32_t last_ntp_hit_ago;
+ uint32_t last_cmd_hit_ago;
+} RPY_ClientAccesses_Client;
+
+typedef struct {
+ uint32_t n_indices; /* how many indices there are in the server's table */
+ uint32_t next_index; /* the index 1 beyond those processed on this call */
+ uint32_t n_clients; /* the number of valid entries in the following array */
+ RPY_ClientAccesses_Client clients[MAX_CLIENT_ACCESSES];
+ int32_t EOR;
+} RPY_ClientAccessesByIndex;
+
+typedef struct {
+ uint32_t ntp_hits;
+ uint32_t cmd_hits;
+ uint32_t ntp_drops;
+ uint32_t cmd_drops;
+ uint32_t log_drops;
+ int32_t EOR;
+} RPY_ServerStats;
+
+#define MAX_MANUAL_LIST_SAMPLES 16
+
+typedef struct {
+ Timespec when;
+ Float slewed_offset;
+ Float orig_offset;
+ Float residual;
+} RPY_ManualListSample;
+
+typedef struct {
+ uint32_t n_samples;
+ RPY_ManualListSample samples[MAX_MANUAL_LIST_SAMPLES];
+ int32_t EOR;
+} RPY_ManualList;
+
+typedef struct {
+ int32_t online;
+ int32_t offline;
+ int32_t burst_online;
+ int32_t burst_offline;
+ int32_t unresolved;
+ 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;
+
+#define RPY_NTP_FLAGS_TESTS 0x3ff
+#define RPY_NTP_FLAG_INTERLEAVED 0x4000
+#define RPY_NTP_FLAG_AUTHENTICATED 0x8000
+
+typedef struct {
+ IPAddr remote_addr;
+ IPAddr local_addr;
+ uint16_t remote_port;
+ uint8_t leap;
+ uint8_t version;
+ uint8_t mode;
+ uint8_t stratum;
+ int8_t poll;
+ int8_t precision;
+ Float root_delay;
+ Float root_dispersion;
+ uint32_t ref_id;
+ Timespec ref_time;
+ Float offset;
+ Float peer_delay;
+ Float peer_dispersion;
+ Float response_time;
+ Float jitter_asymmetry;
+ uint16_t flags;
+ uint8_t tx_tss_char;
+ uint8_t rx_tss_char;
+ uint32_t total_tx_count;
+ uint32_t total_rx_count;
+ uint32_t total_valid_count;
+ uint32_t reserved[4];
+ int32_t EOR;
+} RPY_NTPData;
+
+typedef struct {
+ uint8_t version;
+ uint8_t pkt_type;
+ uint8_t res1;
+ uint8_t res2;
+ uint16_t command; /* Which command is being replied to */
+ uint16_t reply; /* Which format of reply this is */
+ uint16_t status; /* Status of command processing */
+ uint16_t pad1; /* Padding for compatibility and 4 byte alignment */
+ uint16_t pad2;
+ uint16_t pad3;
+ uint32_t sequence; /* Echo of client's sequence number */
+ uint32_t pad4;
+ uint32_t pad5;
+
+ union {
+ RPY_Null null;
+ RPY_N_Sources n_sources;
+ RPY_Source_Data source_data;
+ RPY_ManualTimestamp manual_timestamp;
+ RPY_Tracking tracking;
+ RPY_Sourcestats sourcestats;
+ RPY_Rtc rtc;
+ RPY_ClientAccessesByIndex client_accesses_by_index;
+ RPY_ServerStats server_stats;
+ RPY_ManualList manual_list;
+ RPY_Activity activity;
+ RPY_Smoothing smoothing;
+ RPY_NTPData ntp_data;
+ } data; /* Reply specific parameters */
+
+} CMD_Reply;
+
+/* ================================================== */
+
+#endif /* GOT_CANDM_H */
diff --git a/client.c b/client.c
new file mode 100644
index 0000000..029860c
--- /dev/null
+++ b/client.c
@@ -0,0 +1,3290 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow 1997-2003
+ * Copyright (C) Lonnie Abelbeck 2016, 2018
+ * Copyright (C) Miroslav Lichvar 2009-2018
+ *
+ * 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.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Command line client for configuring the daemon and obtaining status
+ from it whilst running.
+ */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "array.h"
+#include "candm.h"
+#include "logging.h"
+#include "memory.h"
+#include "nameserv.h"
+#include "getdate.h"
+#include "cmdparse.h"
+#include "pktlength.h"
+#include "util.h"
+
+#ifdef FEAT_READLINE
+#ifdef USE_EDITLINE
+#include <editline/readline.h>
+#else
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+#endif
+
+/* ================================================== */
+
+union sockaddr_all {
+ struct sockaddr_in in4;
+#ifdef FEAT_IPV6
+ struct sockaddr_in6 in6;
+#endif
+ struct sockaddr_un un;
+ struct sockaddr sa;
+};
+
+static ARR_Instance sockaddrs;
+
+static int sock_fd = -1;
+
+static int quit = 0;
+
+static int on_terminal = 0;
+
+static int no_dns = 0;
+
+static int csv_mode = 0;
+
+/* ================================================== */
+/* Log a message. This is a minimalistic replacement of the logging.c
+ implementation to avoid linking with it and other modules. */
+
+int log_debug_enabled = 0;
+
+void LOG_Message(LOG_Severity severity,
+#if DEBUG > 0
+ int line_number, const char *filename, const char *function_name,
+#endif
+ const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ putc('\n', stderr);
+ va_end(ap);
+}
+
+/* ================================================== */
+/* Read a single line of commands from standard input */
+
+#ifdef FEAT_READLINE
+static char **command_name_completion(const char *text, int start, int end);
+#endif
+
+static char *
+read_line(void)
+{
+ static char line[2048];
+ static const char *prompt = "chronyc> ";
+
+ if (on_terminal) {
+#ifdef FEAT_READLINE
+ char *cmd;
+
+ rl_attempted_completion_function = command_name_completion;
+ rl_basic_word_break_characters = " \t\n\r";
+
+ /* save line only if not empty */
+ cmd = readline(prompt);
+ if( cmd == NULL ) return( NULL );
+
+ /* user pressed return */
+ if( *cmd != '\0' ) {
+ strncpy(line, cmd, sizeof(line) - 1);
+ line[sizeof(line) - 1] = '\0';
+ add_history(cmd);
+ /* free the buffer allocated by readline */
+ Free(cmd);
+ } else {
+ /* simulate the user has entered an empty line */
+ *line = '\0';
+ }
+ return( line );
+#else
+ printf("%s", prompt);
+ fflush(stdout);
+#endif
+ }
+ if (fgets(line, sizeof(line), stdin)) {
+ return line;
+ } else {
+ return NULL;
+ }
+
+}
+
+/* ================================================== */
+
+static ARR_Instance
+get_sockaddrs(const char *hostnames, int port)
+{
+ ARR_Instance addrs;
+ char *hostname, *s1, *s2;
+ IPAddr ip_addrs[DNS_MAX_ADDRESSES];
+ union sockaddr_all *addr;
+ int i;
+
+ addrs = ARR_CreateInstance(sizeof (union sockaddr_all));
+ s1 = Strdup(hostnames);
+
+ /* Parse the comma-separated list of hostnames */
+ for (hostname = s1; hostname && *hostname; hostname = s2) {
+ s2 = strchr(hostname, ',');
+ if (s2)
+ *s2++ = '\0';
+
+ /* hostname starting with / is considered a path of Unix domain socket */
+ if (hostname[0] == '/') {
+ addr = (union sockaddr_all *)ARR_GetNewElement(addrs);
+ if (snprintf(addr->un.sun_path, sizeof (addr->un.sun_path), "%s", hostname) >=
+ sizeof (addr->un.sun_path))
+ LOG_FATAL("Unix socket path too long");
+ addr->un.sun_family = AF_UNIX;
+ } else {
+ if (DNS_Name2IPAddress(hostname, ip_addrs, DNS_MAX_ADDRESSES) != DNS_Success) {
+ DEBUG_LOG("Could not get IP address for %s", hostname);
+ continue;
+ }
+
+ for (i = 0; i < DNS_MAX_ADDRESSES && ip_addrs[i].family != IPADDR_UNSPEC; i++) {
+ addr = (union sockaddr_all *)ARR_GetNewElement(addrs);
+ UTI_IPAndPortToSockaddr(&ip_addrs[i], port, (struct sockaddr *)addr);
+ DEBUG_LOG("Resolved %s to %s", hostname, UTI_IPToString(&ip_addrs[i]));
+ }
+ }
+ }
+
+ Free(s1);
+ return addrs;
+}
+
+/* ================================================== */
+/* Initialise the socket used to talk to the daemon */
+
+static int
+prepare_socket(union sockaddr_all *addr)
+{
+ socklen_t addr_len;
+ char *dir;
+
+ switch (addr->sa.sa_family) {
+ case AF_UNIX:
+ addr_len = sizeof (addr->un);
+ break;
+ case AF_INET:
+ addr_len = sizeof (addr->in4);
+ break;
+#ifdef FEAT_IPV6
+ case AF_INET6:
+ addr_len = sizeof (addr->in6);
+ break;
+#endif
+ default:
+ assert(0);
+ }
+
+ sock_fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0);
+
+ if (sock_fd < 0) {
+ DEBUG_LOG("Could not create socket : %s", strerror(errno));
+ return 0;
+ }
+
+ if (addr->sa.sa_family == AF_UNIX) {
+ struct sockaddr_un sa_un;
+
+ /* Construct path of our socket. Use the same directory as the server
+ socket and include our process ID to allow multiple chronyc instances
+ running at the same time. */
+ dir = UTI_PathToDir(addr->un.sun_path);
+ if (snprintf(sa_un.sun_path, sizeof (sa_un.sun_path),
+ "%s/chronyc.%d.sock", dir, (int)getpid()) >= sizeof (sa_un.sun_path))
+ LOG_FATAL("Unix socket path too long");
+ Free(dir);
+
+ sa_un.sun_family = AF_UNIX;
+ unlink(sa_un.sun_path);
+
+ /* Bind the socket to the path */
+ if (bind(sock_fd, (struct sockaddr *)&sa_un, sizeof (sa_un)) < 0) {
+ DEBUG_LOG("Could not bind socket : %s", strerror(errno));
+ return 0;
+ }
+
+ /* Allow server without root privileges to send replies to our socket */
+ if (chmod(sa_un.sun_path, 0666) < 0) {
+ DEBUG_LOG("Could not change socket permissions : %s", strerror(errno));
+ return 0;
+ }
+ }
+
+ if (connect(sock_fd, &addr->sa, addr_len) < 0) {
+ DEBUG_LOG("Could not connect socket : %s", strerror(errno));
+ return 0;
+ }
+
+ return 1;
+}
+
+/* ================================================== */
+
+static void
+close_io(void)
+{
+ union sockaddr_all addr;
+ socklen_t addr_len = sizeof (addr);
+
+ if (sock_fd < 0)
+ return;
+
+ /* Remove our Unix domain socket */
+ if (getsockname(sock_fd, &addr.sa, &addr_len) < 0)
+ LOG_FATAL("getsockname() failed : %s", strerror(errno));
+ if (addr_len <= sizeof (addr) && addr_len > sizeof (addr.sa.sa_family) &&
+ addr.sa.sa_family == AF_UNIX)
+ unlink(addr.un.sun_path);
+
+ close(sock_fd);
+ sock_fd = -1;
+}
+
+/* ================================================== */
+
+static int
+open_io(void)
+{
+ static unsigned int address_index = 0;
+ union sockaddr_all *addr;
+
+ /* If a socket is already opened, close it and try the next address */
+ if (sock_fd >= 0) {
+ close_io();
+ address_index++;
+ }
+
+ /* Find an address for which a socket can be opened and connected */
+ for (; address_index < ARR_GetSize(sockaddrs); address_index++) {
+ addr = (union sockaddr_all *)ARR_GetElement(sockaddrs, address_index);
+ DEBUG_LOG("Opening connection to %s", UTI_SockaddrToString(&addr->sa));
+
+ if (prepare_socket(addr))
+ return 1;
+
+ close_io();
+ }
+
+ return 0;
+}
+
+/* ================================================== */
+
+static void
+bits_to_mask(int bits, int family, IPAddr *mask)
+{
+ int i;
+
+ mask->family = family;
+ switch (family) {
+ case IPADDR_INET4:
+ if (bits > 32 || bits < 0)
+ bits = 32;
+ if (bits > 0) {
+ mask->addr.in4 = -1;
+ mask->addr.in4 <<= 32 - bits;
+ } else {
+ mask->addr.in4 = 0;
+ }
+ break;
+ case IPADDR_INET6:
+ if (bits > 128 || bits < 0)
+ bits = 128;
+ for (i = 0; i < bits / 8; i++)
+ mask->addr.in6[i] = 0xff;
+ if (i < 16)
+ mask->addr.in6[i++] = (0xff << (8 - bits % 8)) & 0xff;
+ for (; i < 16; i++)
+ mask->addr.in6[i] = 0x0;
+ break;
+ default:
+ assert(0);
+ }
+}
+
+/* ================================================== */
+
+static int
+read_mask_address(char *line, IPAddr *mask, IPAddr *address)
+{
+ unsigned int bits;
+ char *p, *q;
+
+ p = line;
+ if (!*p) {
+ mask->family = address->family = IPADDR_UNSPEC;
+ return 1;
+ } else {
+ q = strchr(p, '/');
+ if (q) {
+ *q++ = 0;
+ if (UTI_StringToIP(p, mask)) {
+ p = q;
+ if (UTI_StringToIP(p, address)) {
+ if (address->family == mask->family)
+ return 1;
+ } else if (sscanf(p, "%u", &bits) == 1) {
+ *address = *mask;
+ bits_to_mask(bits, address->family, mask);
+ return 1;
+ }
+ }
+ } else {
+ if (DNS_Name2IPAddress(p, address, 1) == DNS_Success) {
+ bits_to_mask(-1, address->family, mask);
+ return 1;
+ } else {
+ LOG(LOGS_ERR, "Could not get address for hostname");
+ return 0;
+ }
+ }
+ }
+
+ LOG(LOGS_ERR, "Invalid syntax for mask/address");
+ return 0;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_offline(CMD_Request *msg, char *line)
+{
+ IPAddr mask, address;
+ int ok;
+
+ if (read_mask_address(line, &mask, &address)) {
+ UTI_IPHostToNetwork(&mask, &msg->data.offline.mask);
+ UTI_IPHostToNetwork(&address, &msg->data.offline.address);
+ msg->command = htons(REQ_OFFLINE);
+ ok = 1;
+ } else {
+ ok = 0;
+ }
+
+ return ok;
+
+}
+
+/* ================================================== */
+
+
+static int
+process_cmd_online(CMD_Request *msg, char *line)
+{
+ IPAddr mask, address;
+ int ok;
+
+ if (read_mask_address(line, &mask, &address)) {
+ UTI_IPHostToNetwork(&mask, &msg->data.online.mask);
+ UTI_IPHostToNetwork(&address, &msg->data.online.address);
+ msg->command = htons(REQ_ONLINE);
+ ok = 1;
+ } else {
+ ok = 0;
+ }
+
+ return ok;
+
+}
+
+/* ================================================== */
+
+static void
+process_cmd_onoffline(CMD_Request *msg, char *line)
+{
+ msg->command = htons(REQ_ONOFFLINE);
+}
+
+/* ================================================== */
+
+static int
+read_address_integer(char *line, IPAddr *address, int *value)
+{
+ char *hostname;
+ int ok = 0;
+
+ hostname = line;
+ line = CPS_SplitWord(line);
+
+ if (sscanf(line, "%d", value) != 1) {
+ LOG(LOGS_ERR, "Invalid syntax for address value");
+ ok = 0;
+ } else {
+ if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
+ LOG(LOGS_ERR, "Could not get address for hostname");
+ ok = 0;
+ } else {
+ ok = 1;
+ }
+ }
+
+ return ok;
+
+}
+
+
+/* ================================================== */
+
+static int
+read_address_double(char *line, IPAddr *address, double *value)
+{
+ char *hostname;
+ int ok = 0;
+
+ hostname = line;
+ line = CPS_SplitWord(line);
+
+ if (sscanf(line, "%lf", value) != 1) {
+ LOG(LOGS_ERR, "Invalid syntax for address value");
+ ok = 0;
+ } else {
+ if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
+ LOG(LOGS_ERR, "Could not get address for hostname");
+ ok = 0;
+ } else {
+ ok = 1;
+ }
+ }
+
+ return ok;
+
+}
+
+
+/* ================================================== */
+
+static int
+process_cmd_minpoll(CMD_Request *msg, char *line)
+{
+ IPAddr address;
+ int minpoll;
+ int ok;
+
+ if (read_address_integer(line, &address, &minpoll)) {
+ UTI_IPHostToNetwork(&address, &msg->data.modify_minpoll.address);
+ msg->data.modify_minpoll.new_minpoll = htonl(minpoll);
+ msg->command = htons(REQ_MODIFY_MINPOLL);
+ ok = 1;
+ } else {
+ ok = 0;
+ }
+
+ return ok;
+
+}
+
+/* ================================================== */
+
+static int
+process_cmd_maxpoll(CMD_Request *msg, char *line)
+{
+ IPAddr address;
+ int maxpoll;
+ int ok;
+
+ if (read_address_integer(line, &address, &maxpoll)) {
+ UTI_IPHostToNetwork(&address, &msg->data.modify_maxpoll.address);
+ msg->data.modify_maxpoll.new_maxpoll = htonl(maxpoll);
+ msg->command = htons(REQ_MODIFY_MAXPOLL);
+ ok = 1;
+ } else {
+ ok = 0;
+ }
+
+ return ok;
+
+}
+
+/* ================================================== */
+
+static int
+process_cmd_maxdelay(CMD_Request *msg, char *line)
+{
+ IPAddr address;
+ double max_delay;
+ int ok;
+
+ if (read_address_double(line, &address, &max_delay)) {
+ UTI_IPHostToNetwork(&address, &msg->data.modify_maxdelay.address);
+ msg->data.modify_maxdelay.new_max_delay = UTI_FloatHostToNetwork(max_delay);
+ msg->command = htons(REQ_MODIFY_MAXDELAY);
+ ok = 1;
+ } else {
+ ok = 0;
+ }
+
+ return ok;
+
+}
+
+/* ================================================== */
+
+static int
+process_cmd_maxdelaydevratio(CMD_Request *msg, char *line)
+{
+ IPAddr address;
+ double max_delay_dev_ratio;
+ int ok;
+
+ if (read_address_double(line, &address, &max_delay_dev_ratio)) {
+ UTI_IPHostToNetwork(&address, &msg->data.modify_maxdelaydevratio.address);
+ msg->data.modify_maxdelayratio.new_max_delay_ratio = UTI_FloatHostToNetwork(max_delay_dev_ratio);
+ msg->command = htons(REQ_MODIFY_MAXDELAYDEVRATIO);
+ ok = 1;
+ } else {
+ ok = 0;
+ }
+
+ return ok;
+
+}
+
+/* ================================================== */
+
+static int
+process_cmd_maxdelayratio(CMD_Request *msg, char *line)
+{
+ IPAddr address;
+ double max_delay_ratio;
+ int ok;
+
+ if (read_address_double(line, &address, &max_delay_ratio)) {
+ UTI_IPHostToNetwork(&address, &msg->data.modify_maxdelayratio.address);
+ msg->data.modify_maxdelayratio.new_max_delay_ratio = UTI_FloatHostToNetwork(max_delay_ratio);
+ msg->command = htons(REQ_MODIFY_MAXDELAYRATIO);
+ ok = 1;
+ } else {
+ ok = 0;
+ }
+
+ return ok;
+
+}
+
+/* ================================================== */
+
+static int
+process_cmd_minstratum(CMD_Request *msg, char *line)
+{
+ IPAddr address;
+ int min_stratum;
+ int ok;
+
+ if (read_address_integer(line, &address, &min_stratum)) {
+ UTI_IPHostToNetwork(&address, &msg->data.modify_minstratum.address);
+ msg->data.modify_minstratum.new_min_stratum = htonl(min_stratum);
+ msg->command = htons(REQ_MODIFY_MINSTRATUM);
+ ok = 1;
+ } else {
+ ok = 0;
+ }
+
+ return ok;
+
+}
+
+/* ================================================== */
+
+static int
+process_cmd_polltarget(CMD_Request *msg, char *line)
+{
+ IPAddr address;
+ int poll_target;
+ int ok;
+
+ if (read_address_integer(line, &address, &poll_target)) {
+ UTI_IPHostToNetwork(&address, &msg->data.modify_polltarget.address);
+ msg->data.modify_polltarget.new_poll_target = htonl(poll_target);
+ msg->command = htons(REQ_MODIFY_POLLTARGET);
+ ok = 1;
+ } else {
+ ok = 0;
+ }
+
+ return ok;
+
+}
+
+/* ================================================== */
+
+static int
+process_cmd_maxupdateskew(CMD_Request *msg, char *line)
+{
+ int ok;
+ double new_max_update_skew;
+
+ if (sscanf(line, "%lf", &new_max_update_skew) == 1) {
+ msg->data.modify_maxupdateskew.new_max_update_skew = UTI_FloatHostToNetwork(new_max_update_skew);
+ msg->command = htons(REQ_MODIFY_MAXUPDATESKEW);
+ ok = 1;
+ } else {
+ ok = 0;
+ }
+
+ return ok;
+
+}
+
+/* ================================================== */
+
+static void
+process_cmd_dump(CMD_Request *msg, char *line)
+{
+ msg->command = htons(REQ_DUMP);
+ msg->data.dump.pad = htonl(0);
+}
+
+/* ================================================== */
+
+static void
+process_cmd_writertc(CMD_Request *msg, char *line)
+{
+ msg->command = htons(REQ_WRITERTC);
+}
+
+/* ================================================== */
+
+static void
+process_cmd_trimrtc(CMD_Request *msg, char *line)
+{
+ msg->command = htons(REQ_TRIMRTC);
+}
+
+/* ================================================== */
+
+static void
+process_cmd_cyclelogs(CMD_Request *msg, char *line)
+{
+ msg->command = htons(REQ_CYCLELOGS);
+}
+
+/* ================================================== */
+
+static int
+process_cmd_burst(CMD_Request *msg, char *line)
+{
+ int n_good_samples, n_total_samples;
+ char *s1, *s2;
+ IPAddr address, mask;
+
+ s1 = line;
+ s2 = CPS_SplitWord(s1);
+ CPS_SplitWord(s2);
+
+ if (sscanf(s1, "%d/%d", &n_good_samples, &n_total_samples) != 2) {
+ LOG(LOGS_ERR, "Invalid syntax for burst command");
+ return 0;
+ }
+
+ mask.family = address.family = IPADDR_UNSPEC;
+ if (*s2 && !read_mask_address(s2, &mask, &address)) {
+ return 0;
+ }
+
+ msg->command = htons(REQ_BURST);
+ msg->data.burst.n_good_samples = ntohl(n_good_samples);
+ msg->data.burst.n_total_samples = ntohl(n_total_samples);
+
+ UTI_IPHostToNetwork(&mask, &msg->data.burst.mask);
+ UTI_IPHostToNetwork(&address, &msg->data.burst.address);
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_local(CMD_Request *msg, char *line)
+{
+ int on_off, stratum = 0, orphan = 0;
+ double distance = 0.0;
+
+ if (!strcmp(line, "off")) {
+ on_off = 0;
+ } else if (CPS_ParseLocal(line, &stratum, &orphan, &distance)) {
+ on_off = 1;
+ } else {
+ LOG(LOGS_ERR, "Invalid syntax for local command");
+ return 0;
+ }
+
+ msg->command = htons(REQ_LOCAL2);
+ msg->data.local.on_off = htonl(on_off);
+ msg->data.local.stratum = htonl(stratum);
+ msg->data.local.distance = UTI_FloatHostToNetwork(distance);
+ msg->data.local.orphan = htonl(orphan);
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_manual(CMD_Request *msg, const char *line)
+{
+ const char *p;
+
+ p = line;
+
+ if (!strcmp(p, "off")) {
+ msg->data.manual.option = htonl(0);
+ } else if (!strcmp(p, "on")) {
+ msg->data.manual.option = htonl(1);
+ } else if (!strcmp(p, "reset")) {
+ msg->data.manual.option = htonl(2);
+ } else {
+ LOG(LOGS_ERR, "Invalid syntax for manual command");
+ return 0;
+ }
+ msg->command = htons(REQ_MANUAL);
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+parse_allow_deny(CMD_Request *msg, char *line)
+{
+ unsigned long a, b, c, d;
+ int n, specified_subnet_bits;
+ IPAddr ip;
+ char *p;
+
+ p = line;
+ if (!*p) {
+ /* blank line - applies to all addresses */
+ ip.family = IPADDR_UNSPEC;
+ UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip);
+ msg->data.allow_deny.subnet_bits = htonl(0);
+ } else {
+ char *slashpos;
+ slashpos = strchr(p, '/');
+ if (slashpos) *slashpos = 0;
+
+ n = 0;
+ if (!UTI_StringToIP(p, &ip) &&
+ (n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) <= 0) {
+
+ /* Try to parse as the name of a machine */
+ if (slashpos || DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
+ LOG(LOGS_ERR, "Could not read address");
+ return 0;
+ } else {
+ UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip);
+ if (ip.family == IPADDR_INET6)
+ msg->data.allow_deny.subnet_bits = htonl(128);
+ else
+ msg->data.allow_deny.subnet_bits = htonl(32);
+ }
+ } else {
+
+ if (n == 0) {
+ if (ip.family == IPADDR_INET6)
+ msg->data.allow_deny.subnet_bits = htonl(128);
+ else
+ msg->data.allow_deny.subnet_bits = htonl(32);
+ } else {
+ ip.family = IPADDR_INET4;
+
+ a &= 0xff;
+ b &= 0xff;
+ c &= 0xff;
+ d &= 0xff;
+
+ switch (n) {
+ case 1:
+ ip.addr.in4 = htonl((a<<24));
+ msg->data.allow_deny.subnet_bits = htonl(8);
+ break;
+ case 2:
+ ip.addr.in4 = htonl((a<<24) | (b<<16));
+ msg->data.allow_deny.subnet_bits = htonl(16);
+ break;
+ case 3:
+ ip.addr.in4 = htonl((a<<24) | (b<<16) | (c<<8));
+ msg->data.allow_deny.subnet_bits = htonl(24);
+ break;
+ case 4:
+ ip.addr.in4 = htonl((a<<24) | (b<<16) | (c<<8) | d);
+ msg->data.allow_deny.subnet_bits = htonl(32);
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip);
+
+ if (slashpos) {
+ n = sscanf(slashpos+1, "%d", &specified_subnet_bits);
+ if (n == 1) {
+ msg->data.allow_deny.subnet_bits = htonl(specified_subnet_bits);
+ } else {
+ LOG(LOGS_WARN, "Warning: badly formatted subnet size, using %d",
+ (int)ntohl(msg->data.allow_deny.subnet_bits));
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_allow(CMD_Request *msg, char *line)
+{
+ int status;
+ msg->command = htons(REQ_ALLOW);
+ status = parse_allow_deny(msg, line);
+ return status;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_allowall(CMD_Request *msg, char *line)
+{
+ int status;
+ msg->command = htons(REQ_ALLOWALL);
+ status = parse_allow_deny(msg, line);
+ return status;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_deny(CMD_Request *msg, char *line)
+{
+ int status;
+ msg->command = htons(REQ_DENY);
+ status = parse_allow_deny(msg, line);
+ return status;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_denyall(CMD_Request *msg, char *line)
+{
+ int status;
+ msg->command = htons(REQ_DENYALL);
+ status = parse_allow_deny(msg, line);
+ return status;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_cmdallow(CMD_Request *msg, char *line)
+{
+ int status;
+ msg->command = htons(REQ_CMDALLOW);
+ status = parse_allow_deny(msg, line);
+ return status;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_cmdallowall(CMD_Request *msg, char *line)
+{
+ int status;
+ msg->command = htons(REQ_CMDALLOWALL);
+ status = parse_allow_deny(msg, line);
+ return status;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_cmddeny(CMD_Request *msg, char *line)
+{
+ int status;
+ msg->command = htons(REQ_CMDDENY);
+ status = parse_allow_deny(msg, line);
+ return status;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_cmddenyall(CMD_Request *msg, char *line)
+{
+ int status;
+ msg->command = htons(REQ_CMDDENYALL);
+ status = parse_allow_deny(msg, line);
+ return status;
+}
+
+/* ================================================== */
+
+static int
+accheck_getaddr(char *line, IPAddr *addr)
+{
+ unsigned long a, b, c, d;
+ IPAddr ip;
+ char *p;
+ p = line;
+ if (!*p) {
+ return 0;
+ } else {
+ if (sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d) == 4) {
+ addr->family = IPADDR_INET4;
+ addr->addr.in4 = (a<<24) | (b<<16) | (c<<8) | d;
+ return 1;
+ } else {
+ if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
+ return 0;
+ } else {
+ *addr = ip;
+ return 1;
+ }
+ }
+ }
+}
+
+/* ================================================== */
+
+static int
+process_cmd_accheck(CMD_Request *msg, char *line)
+{
+ IPAddr ip;
+ msg->command = htons(REQ_ACCHECK);
+ if (accheck_getaddr(line, &ip)) {
+ UTI_IPHostToNetwork(&ip, &msg->data.ac_check.ip);
+ return 1;
+ } else {
+ LOG(LOGS_ERR, "Could not read address");
+ return 0;
+ }
+}
+
+/* ================================================== */
+
+static int
+process_cmd_cmdaccheck(CMD_Request *msg, char *line)
+{
+ IPAddr ip;
+ msg->command = htons(REQ_CMDACCHECK);
+ if (accheck_getaddr(line, &ip)) {
+ UTI_IPHostToNetwork(&ip, &msg->data.ac_check.ip);
+ return 1;
+ } else {
+ LOG(LOGS_ERR, "Could not read address");
+ return 0;
+ }
+}
+
+/* ================================================== */
+
+static void
+process_cmd_dfreq(CMD_Request *msg, char *line)
+{
+ double dfreq;
+ msg->command = htons(REQ_DFREQ);
+ if (sscanf(line, "%lf", &dfreq) == 1) {
+ msg->data.dfreq.dfreq = UTI_FloatHostToNetwork(dfreq);
+ } else {
+ msg->data.dfreq.dfreq = UTI_FloatHostToNetwork(0.0);
+ }
+}
+
+/* ================================================== */
+
+static void
+cvt_to_sec_usec(double x, long *sec, long *usec) {
+ long s, us;
+ s = (long) x;
+ us = (long)(0.5 + 1.0e6 * (x - (double) s));
+ while (us >= 1000000) {
+ us -= 1000000;
+ s += 1;
+ }
+ while (us < 0) {
+ us += 1000000;
+ s -= 1;
+ }
+
+ *sec = s;
+ *usec = us;
+}
+
+/* ================================================== */
+
+static void
+process_cmd_doffset(CMD_Request *msg, char *line)
+{
+ double doffset;
+ long sec, usec;
+ msg->command = htons(REQ_DOFFSET);
+ if (sscanf(line, "%lf", &doffset) == 1) {
+ cvt_to_sec_usec(doffset, &sec, &usec);
+ msg->data.doffset.sec = htonl(sec);
+ msg->data.doffset.usec = htonl(usec);
+ } else {
+ msg->data.doffset.sec = htonl(0);
+ msg->data.doffset.usec = htonl(0);
+ }
+}
+
+/* ================================================== */
+
+static int
+process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
+{
+ CPS_NTP_Source data;
+ IPAddr ip_addr;
+ int result = 0, status;
+ const char *opt_name;
+
+ status = CPS_ParseNTPSourceAdd(line, &data);
+ switch (status) {
+ case 0:
+ LOG(LOGS_ERR, "Invalid syntax for add command");
+ break;
+ default:
+ if (DNS_Name2IPAddress(data.name, &ip_addr, 1) != DNS_Success) {
+ LOG(LOGS_ERR, "Invalid host/IP address");
+ break;
+ }
+
+ opt_name = NULL;
+ if (opt_name) {
+ LOG(LOGS_ERR, "%s can't be set in chronyc", opt_name);
+ 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);
+ msg->data.ntp_source.maxpoll = htonl(data.params.maxpoll);
+ msg->data.ntp_source.presend_minpoll = htonl(data.params.presend_minpoll);
+ msg->data.ntp_source.min_stratum = htonl(data.params.min_stratum);
+ msg->data.ntp_source.poll_target = htonl(data.params.poll_target);
+ msg->data.ntp_source.version = htonl(data.params.version);
+ msg->data.ntp_source.max_sources = htonl(data.params.max_sources);
+ msg->data.ntp_source.min_samples = htonl(data.params.min_samples);
+ msg->data.ntp_source.max_samples = htonl(data.params.max_samples);
+ msg->data.ntp_source.authkey = htonl(data.params.authkey);
+ msg->data.ntp_source.max_delay = UTI_FloatHostToNetwork(data.params.max_delay);
+ msg->data.ntp_source.max_delay_ratio = UTI_FloatHostToNetwork(data.params.max_delay_ratio);
+ msg->data.ntp_source.max_delay_dev_ratio =
+ UTI_FloatHostToNetwork(data.params.max_delay_dev_ratio);
+ msg->data.ntp_source.min_delay = UTI_FloatHostToNetwork(data.params.min_delay);
+ msg->data.ntp_source.asymmetry = UTI_FloatHostToNetwork(data.params.asymmetry);
+ msg->data.ntp_source.offset = UTI_FloatHostToNetwork(data.params.offset);
+ msg->data.ntp_source.flags = htonl(
+ (data.params.connectivity == SRC_ONLINE ? REQ_ADDSRC_ONLINE : 0) |
+ (data.params.auto_offline ? REQ_ADDSRC_AUTOOFFLINE : 0) |
+ (data.params.iburst ? REQ_ADDSRC_IBURST : 0) |
+ (data.params.interleaved ? REQ_ADDSRC_INTERLEAVED : 0) |
+ (data.params.burst ? REQ_ADDSRC_BURST : 0) |
+ (data.params.sel_options & SRC_SELECT_PREFER ? REQ_ADDSRC_PREFER : 0) |
+ (data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) |
+ (data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) |
+ (data.params.sel_options & SRC_SELECT_REQUIRE ? REQ_ADDSRC_REQUIRE : 0));
+ msg->data.ntp_source.filter_length = htonl(data.params.filter_length);
+ memset(msg->data.ntp_source.reserved, 0, sizeof (msg->data.ntp_source.reserved));
+
+ result = 1;
+
+ break;
+ }
+
+ return result;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_add_server(CMD_Request *msg, char *line)
+{
+ msg->command = htons(REQ_ADD_SERVER3);
+ return process_cmd_add_server_or_peer(msg, line);
+}
+
+/* ================================================== */
+
+static int
+process_cmd_add_peer(CMD_Request *msg, char *line)
+{
+ msg->command = htons(REQ_ADD_PEER3);
+ return process_cmd_add_server_or_peer(msg, line);
+}
+
+/* ================================================== */
+
+static int
+process_cmd_delete(CMD_Request *msg, char *line)
+{
+ char *hostname;
+ int ok = 0;
+ IPAddr address;
+
+ msg->command = htons(REQ_DEL_SOURCE);
+ hostname = line;
+ CPS_SplitWord(line);
+
+ if (!*hostname) {
+ LOG(LOGS_ERR, "Invalid syntax for address");
+ ok = 0;
+ } else {
+ if (DNS_Name2IPAddress(hostname, &address, 1) != DNS_Success) {
+ LOG(LOGS_ERR, "Could not get address for hostname");
+ ok = 0;
+ } else {
+ UTI_IPHostToNetwork(&address, &msg->data.del_source.ip_addr);
+ ok = 1;
+ }
+ }
+
+ return ok;
+
+}
+
+/* ================================================== */
+
+static void
+give_help(void)
+{
+ int line, len;
+ const char *s, cols[] =
+ "System clock:\0\0"
+ "tracking\0Display system time information\0"
+ "makestep\0Correct clock by stepping immediately\0"
+ "makestep <threshold> <updates>\0Configure automatic clock stepping\0"
+ "maxupdateskew <skew>\0Modify maximum valid skew to update frequency\0"
+ "waitsync [<max-tries> [<max-correction> [<max-skew> [<interval>]]]]\0"
+ "Wait until synchronised in specified limits\0"
+ "\0\0"
+ "Time sources:\0\0"
+ "sources [-v]\0Display information about current sources\0"
+ "sourcestats [-v]\0Display statistics about collected measurements\0"
+ "reselect\0Force reselecting synchronisation source\0"
+ "reselectdist <dist>\0Modify reselection distance\0"
+ "\0\0"
+ "NTP sources:\0\0"
+ "activity\0Check how many NTP sources are online/offline\0"
+ "ntpdata [<address>]\0Display information about last valid measurement\0"
+ "add server <address> [options]\0Add new NTP server\0"
+ "add peer <address> [options]\0Add new NTP peer\0"
+ "delete <address>\0Remove server or peer\0"
+ "burst <n-good>/<n-max> [<mask>/<address>]\0Start rapid set of measurements\0"
+ "maxdelay <address> <delay>\0Modify maximum valid sample delay\0"
+ "maxdelayratio <address> <ratio>\0Modify maximum valid delay/minimum ratio\0"
+ "maxdelaydevratio <address> <ratio>\0Modify maximum valid delay/deviation ratio\0"
+ "minpoll <address> <poll>\0Modify minimum polling interval\0"
+ "maxpoll <address> <poll>\0Modify maximum polling interval\0"
+ "minstratum <address> <stratum>\0Modify minimum stratum\0"
+ "offline [<mask>/<address>]\0Set sources in subnet to offline status\0"
+ "online [<mask>/<address>]\0Set sources in subnet to online status\0"
+ "onoffline\0Set all sources to online or offline status\0"
+ "\0according to network configuration\0"
+ "polltarget <address> <target>\0Modify poll target\0"
+ "refresh\0Refresh IP addresses\0"
+ "\0\0"
+ "Manual time input:\0\0"
+ "manual off|on|reset\0Disable/enable/reset settime command\0"
+ "manual list\0Show previous settime entries\0"
+ "manual delete <index>\0Delete previous settime entry\0"
+ "settime <time>\0Set daemon time\0"
+ "\0(e.g. Sep 25, 2015 16:30:05 or 16:30:05)\0"
+ "\0\0NTP access:\0\0"
+ "accheck <address>\0Check whether address is allowed\0"
+ "clients\0Report on clients that have accessed the server\0"
+ "serverstats\0Display statistics of the server\0"
+ "allow [<subnet>]\0Allow access to subnet as a default\0"
+ "allow all [<subnet>]\0Allow access to subnet and all children\0"
+ "deny [<subnet>]\0Deny access to subnet as a default\0"
+ "deny all [<subnet>]\0Deny access to subnet and all children\0"
+ "local [options]\0Serve time even when not synchronised\0"
+ "local off\0Don't serve time when not synchronised\0"
+ "smoothtime reset|activate\0Reset/activate time smoothing\0"
+ "smoothing\0Display current time smoothing state\0"
+ "\0\0"
+ "Monitoring access:\0\0"
+ "cmdaccheck <address>\0Check whether address is allowed\0"
+ "cmdallow [<subnet>]\0Allow access to subnet as a default\0"
+ "cmdallow all [<subnet>]\0Allow access to subnet and all children\0"
+ "cmddeny [<subnet>]\0Deny access to subnet as a default\0"
+ "cmddeny all [<subnet>]\0Deny access to subnet and all children\0"
+ "\0\0"
+ "Real-time clock:\0\0"
+ "rtcdata\0Print current RTC performance parameters\0"
+ "trimrtc\0Correct RTC relative to system clock\0"
+ "writertc\0Save RTC performance parameters to file\0"
+ "\0\0"
+ "Other daemon commands:\0\0"
+ "cyclelogs\0Close and re-open log files\0"
+ "dump\0Dump all measurements to save files\0"
+ "rekey\0Re-read keys from key file\0"
+ "shutdown\0Stop daemon\0"
+ "\0\0"
+ "Client commands:\0\0"
+ "dns -n|+n\0Disable/enable resolving IP addresses to hostnames\0"
+ "dns -4|-6|-46\0Resolve hostnames only to IPv4/IPv6/both addresses\0"
+ "timeout <milliseconds>\0Set initial response timeout\0"
+ "retries <retries>\0Set maximum number of retries\0"
+ "keygen [<id> [<type> [<bits>]]]\0Generate key for key file\0"
+ "exit|quit\0Leave the program\0"
+ "help\0Generate this help\0"
+ "\0";
+
+ /* Indent the second column */
+ for (s = cols, line = 0; s < cols + sizeof (cols); s += len + 1, line++) {
+ len = strlen(s);
+ printf(line % 2 == 0 ? (len >= 28 ? "%s\n%28s" : "%-28s%s") : "%s%s\n",
+ s, "");
+ }
+}
+
+/* ================================================== */
+/* Tab-completion when editline/readline is available */
+
+#ifdef FEAT_READLINE
+
+enum {
+ TAB_COMPLETE_BASE_CMDS,
+ TAB_COMPLETE_ADD_OPTS,
+ TAB_COMPLETE_MANUAL_OPTS,
+ TAB_COMPLETE_SOURCES_OPTS,
+ TAB_COMPLETE_SOURCESTATS_OPTS,
+ TAB_COMPLETE_MAX_INDEX
+};
+
+static int tab_complete_index;
+
+static char *
+command_name_generator(const char *text, int state)
+{
+ const char *name, **names[TAB_COMPLETE_MAX_INDEX];
+ const char *base_commands[] = {
+ "accheck", "activity", "add", "allow", "burst",
+ "clients", "cmdaccheck", "cmdallow", "cmddeny", "cyclelogs", "delete",
+ "deny", "dns", "dump", "exit", "help", "keygen", "local", "makestep",
+ "manual", "maxdelay", "maxdelaydevratio", "maxdelayratio", "maxpoll",
+ "maxupdateskew", "minpoll", "minstratum", "ntpdata", "offline", "online", "onoffline",
+ "polltarget", "quit", "refresh", "rekey", "reselect", "reselectdist",
+ "retries", "rtcdata", "serverstats", "settime", "shutdown", "smoothing",
+ "smoothtime", "sources", "sourcestats",
+ "timeout", "tracking", "trimrtc", "waitsync", "writertc",
+ NULL
+ };
+ const char *add_options[] = { "peer", "server", NULL };
+ const char *manual_options[] = { "on", "off", "delete", "list", "reset", NULL };
+ const char *sources_options[] = { "-v", NULL };
+ const char *sourcestats_options[] = { "-v", NULL };
+ static int list_index, len;
+
+ names[TAB_COMPLETE_BASE_CMDS] = base_commands;
+ names[TAB_COMPLETE_ADD_OPTS] = add_options;
+ names[TAB_COMPLETE_MANUAL_OPTS] = manual_options;
+ names[TAB_COMPLETE_SOURCES_OPTS] = sources_options;
+ names[TAB_COMPLETE_SOURCESTATS_OPTS] = sourcestats_options;
+
+ if (!state) {
+ list_index = 0;
+ len = strlen(text);
+ }
+
+ while ((name = names[tab_complete_index][list_index++])) {
+ if (strncmp(name, text, len) == 0) {
+ return strdup(name);
+ }
+ }
+
+ return NULL;
+}
+
+/* ================================================== */
+
+static char **
+command_name_completion(const char *text, int start, int end)
+{
+ char first[32];
+
+ snprintf(first, MIN(sizeof (first), start + 1), "%s", rl_line_buffer);
+ rl_attempted_completion_over = 1;
+
+ if (!strcmp(first, "add ")) {
+ tab_complete_index = TAB_COMPLETE_ADD_OPTS;
+ } else if (!strcmp(first, "manual ")) {
+ tab_complete_index = TAB_COMPLETE_MANUAL_OPTS;
+ } else if (!strcmp(first, "sources ")) {
+ tab_complete_index = TAB_COMPLETE_SOURCES_OPTS;
+ } else if (!strcmp(first, "sourcestats ")) {
+ tab_complete_index = TAB_COMPLETE_SOURCESTATS_OPTS;
+ } else if (first[0] == '\0') {
+ tab_complete_index = TAB_COMPLETE_BASE_CMDS;
+ } else {
+ return NULL;
+ }
+
+ return rl_completion_matches(text, command_name_generator);
+}
+#endif
+
+/* ================================================== */
+
+static int max_retries = 2;
+static int initial_timeout = 1000;
+static int proto_version = PROTO_VERSION_NUMBER;
+
+/* This is the core protocol module. Complete particular fields in
+ the outgoing packet, send it, wait for a response, handle retries,
+ etc. Returns a Boolean indicating whether the protocol was
+ successful or not.*/
+
+static int
+submit_request(CMD_Request *request, CMD_Reply *reply)
+{
+ int select_status;
+ int recv_status;
+ int read_length;
+ int command_length;
+ int padding_length;
+ struct timespec ts_now, ts_start;
+ struct timeval tv;
+ int n_attempts, new_attempt;
+ double timeout;
+ fd_set rdfd;
+
+ request->pkt_type = PKT_TYPE_CMD_REQUEST;
+ request->res1 = 0;
+ request->res2 = 0;
+ request->pad1 = 0;
+ request->pad2 = 0;
+
+ n_attempts = 0;
+ new_attempt = 1;
+
+ do {
+ if (gettimeofday(&tv, NULL))
+ return 0;
+
+ if (new_attempt) {
+ new_attempt = 0;
+
+ if (n_attempts > max_retries)
+ return 0;
+
+ UTI_TimevalToTimespec(&tv, &ts_start);
+
+ UTI_GetRandomBytes(&request->sequence, sizeof (request->sequence));
+ request->attempt = htons(n_attempts);
+ request->version = proto_version;
+ command_length = PKL_CommandLength(request);
+ padding_length = PKL_CommandPaddingLength(request);
+ assert(command_length > 0 && command_length > padding_length);
+
+ n_attempts++;
+
+ /* Zero the padding to not send any uninitialized data */
+ memset(((char *)request) + command_length - padding_length, 0, padding_length);
+
+ if (sock_fd < 0) {
+ DEBUG_LOG("No socket to send request");
+ return 0;
+ }
+
+ if (send(sock_fd, (void *)request, command_length, 0) < 0) {
+ DEBUG_LOG("Could not send %d bytes : %s", command_length, strerror(errno));
+ return 0;
+ }
+
+ DEBUG_LOG("Sent %d bytes", command_length);
+ }
+
+ UTI_TimevalToTimespec(&tv, &ts_now);
+
+ /* Check if the clock wasn't stepped back */
+ if (UTI_CompareTimespecs(&ts_now, &ts_start) < 0)
+ ts_start = ts_now;
+
+ timeout = initial_timeout / 1000.0 * (1U << (n_attempts - 1)) -
+ UTI_DiffTimespecsToDouble(&ts_now, &ts_start);
+ DEBUG_LOG("Timeout %f seconds", timeout);
+
+ /* Avoid calling select() with an invalid timeout */
+ if (timeout <= 0.0) {
+ new_attempt = 1;
+ continue;
+ }
+
+ UTI_DoubleToTimeval(timeout, &tv);
+
+ FD_ZERO(&rdfd);
+ FD_SET(sock_fd, &rdfd);
+
+ if (quit)
+ return 0;
+
+ select_status = select(sock_fd + 1, &rdfd, NULL, NULL, &tv);
+
+ if (select_status < 0) {
+ DEBUG_LOG("select failed : %s", strerror(errno));
+ return 0;
+ } else if (select_status == 0) {
+ /* Timeout must have elapsed, try a resend? */
+ new_attempt = 1;
+ } else {
+ recv_status = recv(sock_fd, (void *)reply, sizeof(CMD_Reply), 0);
+
+ if (recv_status < 0) {
+ /* If we get connrefused here, it suggests the sendto is
+ going to a dead port */
+ DEBUG_LOG("Could not receive : %s", strerror(errno));
+ new_attempt = 1;
+ } else {
+ DEBUG_LOG("Received %d bytes", recv_status);
+
+ read_length = recv_status;
+
+ /* Check if the header is valid */
+ if (read_length < offsetof(CMD_Reply, data) ||
+ (reply->version != proto_version &&
+ !(reply->version >= PROTO_VERSION_MISMATCH_COMPAT_CLIENT &&
+ ntohs(reply->status) == STT_BADPKTVERSION)) ||
+ reply->pkt_type != PKT_TYPE_CMD_REPLY ||
+ reply->res1 != 0 ||
+ reply->res2 != 0 ||
+ reply->command != request->command ||
+ reply->sequence != request->sequence) {
+ DEBUG_LOG("Invalid reply");
+ continue;
+ }
+
+#if PROTO_VERSION_NUMBER == 6
+ /* Protocol version 5 is similar to 6 except there is no padding.
+ If a version 5 reply with STT_BADPKTVERSION is received,
+ switch our version and try again. */
+ if (proto_version == PROTO_VERSION_NUMBER &&
+ reply->version == PROTO_VERSION_NUMBER - 1) {
+ proto_version = PROTO_VERSION_NUMBER - 1;
+ n_attempts--;
+ new_attempt = 1;
+ continue;
+ }
+#else
+#error unknown compatibility with PROTO_VERSION - 1
+#endif
+
+ /* Check that the packet contains all data it is supposed to have.
+ Unknown responses will always pass this test as their expected
+ length is zero. */
+ if (read_length < PKL_ReplyLength(reply)) {
+ DEBUG_LOG("Reply too short");
+ new_attempt = 1;
+ continue;
+ }
+
+ /* Good packet received, print out results */
+ DEBUG_LOG("Reply cmd=%d reply=%d stat=%d",
+ ntohs(reply->command), ntohs(reply->reply), ntohs(reply->status));
+ break;
+ }
+ }
+ } while (1);
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+request_reply(CMD_Request *request, CMD_Reply *reply, int requested_reply, int verbose)
+{
+ int status;
+
+ while (!submit_request(request, reply)) {
+ /* Try connecting to other addresses before giving up */
+ if (open_io())
+ continue;
+ printf("506 Cannot talk to daemon\n");
+ return 0;
+ }
+
+ status = ntohs(reply->status);
+
+ if (verbose || status != STT_SUCCESS) {
+ switch (status) {
+ case STT_SUCCESS:
+ printf("200 OK");
+ break;
+ case STT_ACCESSALLOWED:
+ printf("208 Access allowed");
+ break;
+ case STT_ACCESSDENIED:
+ printf("209 Access denied");
+ break;
+ case STT_FAILED:
+ printf("500 Failure");
+ break;
+ case STT_UNAUTH:
+ printf("501 Not authorised");
+ break;
+ case STT_INVALID:
+ printf("502 Invalid command");
+ break;
+ case STT_NOSUCHSOURCE:
+ printf("503 No such source");
+ break;
+ case STT_INVALIDTS:
+ printf("504 Duplicate or stale logon detected");
+ break;
+ case STT_NOTENABLED:
+ printf("505 Facility not enabled in daemon");
+ break;
+ case STT_BADSUBNET:
+ printf("507 Bad subnet");
+ break;
+ case STT_NOHOSTACCESS:
+ printf("510 No command access from this host");
+ break;
+ case STT_SOURCEALREADYKNOWN:
+ printf("511 Source already present");
+ break;
+ case STT_TOOMANYSOURCES:
+ printf("512 Too many sources present");
+ break;
+ case STT_NORTC:
+ printf("513 RTC driver not running");
+ break;
+ case STT_BADRTCFILE:
+ printf("514 Can't write RTC parameters");
+ break;
+ case STT_INVALIDAF:
+ printf("515 Invalid address family");
+ break;
+ case STT_BADSAMPLE:
+ printf("516 Sample index out of range");
+ break;
+ case STT_BADPKTVERSION:
+ printf("517 Protocol version mismatch");
+ break;
+ case STT_BADPKTLENGTH:
+ printf("518 Packet length mismatch");
+ break;
+ case STT_INACTIVE:
+ printf("519 Client logging is not active in the daemon");
+ break;
+ default:
+ printf("520 Got unexpected error from daemon");
+ }
+ printf("\n");
+ }
+
+ if (status != STT_SUCCESS &&
+ status != STT_ACCESSALLOWED && status != STT_ACCESSDENIED) {
+ return 0;
+ }
+
+ if (ntohs(reply->reply) != requested_reply) {
+ printf("508 Bad reply from daemon\n");
+ return 0;
+ }
+
+ /* Make sure an unknown response was not requested */
+ assert(PKL_ReplyLength(reply));
+
+ return 1;
+}
+
+/* ================================================== */
+
+static void
+print_seconds(unsigned long s)
+{
+ unsigned long d;
+
+ if (s == (uint32_t)-1) {
+ printf(" -");
+ } else if (s < 1200) {
+ printf("%4lu", s);
+ } else if (s < 36000) {
+ printf("%3lum", s / 60);
+ } else if (s < 345600) {
+ printf("%3luh", s / 3600);
+ } else {
+ d = s / 86400;
+ if (d > 999) {
+ printf("%3luy", d / 365);
+ } else {
+ printf("%3lud", d);
+ }
+ }
+}
+
+/* ================================================== */
+
+static void
+print_nanoseconds(double s)
+{
+ s = fabs(s);
+
+ if (s < 9999.5e-9) {
+ printf("%4.0fns", s * 1e9);
+ } else if (s < 9999.5e-6) {
+ printf("%4.0fus", s * 1e6);
+ } else if (s < 9999.5e-3) {
+ printf("%4.0fms", s * 1e3);
+ } else if (s < 999.5) {
+ printf("%5.1fs", s);
+ } else if (s < 99999.5) {
+ printf("%5.0fs", s);
+ } else if (s < 99999.5 * 60) {
+ printf("%5.0fm", s / 60);
+ } else if (s < 99999.5 * 3600) {
+ printf("%5.0fh", s / 3600);
+ } else if (s < 99999.5 * 3600 * 24) {
+ printf("%5.0fd", s / (3600 * 24));
+ } else {
+ printf("%5.0fy", s / (3600 * 24 * 365));
+ }
+}
+
+/* ================================================== */
+
+static void
+print_signed_nanoseconds(double s)
+{
+ double x;
+
+ x = fabs(s);
+
+ if (x < 9999.5e-9) {
+ printf("%+5.0fns", s * 1e9);
+ } else if (x < 9999.5e-6) {
+ printf("%+5.0fus", s * 1e6);
+ } else if (x < 9999.5e-3) {
+ printf("%+5.0fms", s * 1e3);
+ } else if (x < 999.5) {
+ printf("%+6.1fs", s);
+ } else if (x < 99999.5) {
+ printf("%+6.0fs", s);
+ } else if (x < 99999.5 * 60) {
+ printf("%+6.0fm", s / 60);
+ } else if (x < 99999.5 * 3600) {
+ printf("%+6.0fh", s / 3600);
+ } else if (x < 99999.5 * 3600 * 24) {
+ printf("%+6.0fd", s / (3600 * 24));
+ } else {
+ printf("%+6.0fy", s / (3600 * 24 * 365));
+ }
+}
+
+/* ================================================== */
+
+static void
+print_freq_ppm(double f)
+{
+ if (fabs(f) < 99999.5) {
+ printf("%10.3f", f);
+ } else {
+ printf("%10.0f", f);
+ }
+}
+
+/* ================================================== */
+
+static void
+print_signed_freq_ppm(double f)
+{
+ if (fabs(f) < 99999.5) {
+ printf("%+10.3f", f);
+ } else {
+ printf("%+10.0f", f);
+ }
+}
+
+/* ================================================== */
+
+static void
+print_clientlog_interval(int rate)
+{
+ if (rate >= 127) {
+ printf(" -");
+ } else {
+ printf("%2d", rate);
+ }
+}
+
+/* ================================================== */
+
+static void
+print_header(const char *header)
+{
+ int len;
+
+ if (csv_mode)
+ return;
+
+ printf("%s\n", header);
+
+ len = strlen(header);
+ while (len--)
+ printf("=");
+ printf("\n");
+}
+
+/* ================================================== */
+
+#define REPORT_END 0x1234
+
+/* Print a report. The syntax of the format is similar to printf(), but not all
+ specifiers are supported and some are different! */
+
+static void
+print_report(const char *format, ...)
+{
+ char buf[256];
+ va_list ap;
+ int i, field, sign, width, prec, spec;
+ const char *string;
+ unsigned long long_uinteger;
+ unsigned int uinteger;
+ int integer;
+ struct timespec *ts;
+ struct tm *tm;
+ double dbl;
+
+ va_start(ap, format);
+
+ for (field = 0; ; field++) {
+ /* Search for text between format specifiers and print it
+ if not in the CSV mode */
+ for (i = 0; i < sizeof (buf) && format[i] != '%' && format[i] != '\0'; i++)
+ buf[i] = format[i];
+
+ if (i >= sizeof (buf))
+ break;
+
+ buf[i] = '\0';
+
+ if (!csv_mode)
+ printf("%s", buf);
+
+ if (format[i] == '\0' || format[i + 1] == '\0')
+ break;
+
+ format += i + 1;
+
+ sign = 0;
+ width = 0;
+ prec = 5;
+
+ if (*format == '+' || *format == '-') {
+ sign = 1;
+ format++;
+ }
+
+ if (isdigit((unsigned char)*format)) {
+ width = atoi(format);
+ while (isdigit((unsigned char)*format))
+ format++;
+ }
+
+ if (*format == '.') {
+ format++;
+ prec = atoi(format);
+ while (isdigit((unsigned char)*format))
+ format++;
+ }
+
+ spec = *format;
+ format++;
+
+ /* Disable human-readable formatting in the CSV mode */
+ if (csv_mode) {
+ sign = width = 0;
+
+ if (field > 0)
+ printf(",");
+
+ switch (spec) {
+ case 'C':
+ spec = 'd';
+ break;
+ case 'F':
+ case 'P':
+ prec = 3;
+ spec = 'f';
+ break;
+ case 'O':
+ case 'S':
+ prec = 9;
+ spec = 'f';
+ break;
+ case 'I':
+ spec = 'U';
+ break;
+ case 'T':
+ spec = 'V';
+ break;
+ }
+ }
+
+ switch (spec) {
+ case 'B': /* boolean */
+ integer = va_arg(ap, int);
+ printf("%s", integer ? "Yes" : "No");
+ break;
+ case 'C': /* clientlog interval */
+ integer = va_arg(ap, int);
+ print_clientlog_interval(integer);
+ break;
+ case 'F': /* absolute frequency in ppm with fast/slow keyword */
+ case 'O': /* absolute offset in seconds with fast/slow keyword */
+ dbl = va_arg(ap, double);
+ printf("%*.*f %s %s", width, prec, fabs(dbl),
+ spec == 'O' ? "seconds" : "ppm",
+ (dbl > 0.0) ^ (spec != 'O') ? "slow" : "fast");
+ break;
+ case 'I': /* interval with unit */
+ long_uinteger = va_arg(ap, unsigned long);
+ print_seconds(long_uinteger);
+ break;
+ case 'L': /* leap status */
+ integer = va_arg(ap, int);
+ switch (integer) {
+ case LEAP_Normal:
+ string = "Normal";
+ break;
+ case LEAP_InsertSecond:
+ string = "Insert second";
+ break;
+ case LEAP_DeleteSecond:
+ string = "Delete second";
+ break;
+ case LEAP_Unsynchronised:
+ string = "Not synchronised";
+ break;
+ default:
+ string = "Invalid";
+ break;
+ }
+ printf("%s", string);
+ break;
+ case 'M': /* NTP mode */
+ integer = va_arg(ap, int);
+ switch (integer) {
+ case MODE_ACTIVE:
+ string = "Symmetric active";
+ break;
+ case MODE_PASSIVE:
+ string = "Symmetric passive";
+ break;
+ case MODE_SERVER:
+ string = "Server";
+ break;
+ default:
+ string = "Invalid";
+ break;
+ }
+ printf("%s", string);
+ break;
+ case 'N': /* Timestamp source */
+ integer = va_arg(ap, int);
+ switch (integer) {
+ case 'D':
+ string = "Daemon";
+ break;
+ case 'K':
+ string = "Kernel";
+ break;
+ case 'H':
+ string = "Hardware";
+ break;
+ default:
+ string = "Invalid";
+ break;
+ }
+ printf("%s", string);
+ break;
+ case 'P': /* frequency in ppm */
+ dbl = va_arg(ap, double);
+ if (sign)
+ print_signed_freq_ppm(dbl);
+ else
+ print_freq_ppm(dbl);
+ break;
+ case 'R': /* reference ID in hexdecimal */
+ long_uinteger = va_arg(ap, unsigned long);
+ printf("%08lX", long_uinteger);
+ break;
+ case 'S': /* offset with unit */
+ dbl = va_arg(ap, double);
+ if (sign)
+ print_signed_nanoseconds(dbl);
+ else
+ print_nanoseconds(dbl);
+ break;
+ case 'T': /* timespec as date and time in UTC */
+ ts = va_arg(ap, struct timespec *);
+ tm = gmtime(&ts->tv_sec);
+ if (!tm)
+ break;
+ strftime(buf, sizeof (buf), "%a %b %d %T %Y", tm);
+ printf("%s", buf);
+ break;
+ case 'U': /* unsigned long in decimal */
+ long_uinteger = va_arg(ap, unsigned long);
+ printf("%*lu", width, long_uinteger);
+ break;
+ case 'V': /* timespec as seconds since epoch */
+ ts = va_arg(ap, struct timespec *);
+ printf("%s", UTI_TimespecToString(ts));
+ break;
+ case 'b': /* unsigned int in binary */
+ uinteger = va_arg(ap, unsigned int);
+ for (i = prec - 1; i >= 0; i--)
+ printf("%c", uinteger & 1U << i ? '1' : '0');
+ break;
+
+ /* Classic printf specifiers */
+ case 'c': /* character */
+ integer = va_arg(ap, int);
+ printf("%c", integer);
+ break;
+ case 'd': /* signed int in decimal */
+ integer = va_arg(ap, int);
+ printf("%*d", width, integer);
+ break;
+ case 'f': /* double */
+ dbl = va_arg(ap, double);
+ printf(sign ? "%+*.*f" : "%*.*f", width, prec, dbl);
+ break;
+ case 'o': /* unsigned int in octal */
+ uinteger = va_arg(ap, unsigned int);
+ printf("%*o", width, uinteger);
+ break;
+ case 's': /* string */
+ string = va_arg(ap, const char *);
+ if (sign)
+ printf("%-*s", width, string);
+ else
+ printf("%*s", width, string);
+ break;
+ case 'u': /* unsigned int in decimal */
+ uinteger = va_arg(ap, unsigned int);
+ printf("%*u", width, uinteger);
+ break;
+ }
+ }
+
+ /* Require terminating argument to catch bad type conversions */
+ if (va_arg(ap, int) != REPORT_END)
+ assert(0);
+
+ va_end(ap);
+
+ if (csv_mode)
+ printf("\n");
+}
+
+/* ================================================== */
+
+static void
+print_info_field(const char *format, ...)
+{
+ va_list ap;
+
+ if (csv_mode)
+ return;
+
+ va_start(ap, format);
+ vprintf(format, ap);
+ va_end(ap);
+}
+
+/* ================================================== */
+
+static void
+format_name(char *buf, int size, int trunc_dns, int ref, uint32_t ref_id,
+ IPAddr *ip_addr)
+{
+ if (ref) {
+ snprintf(buf, size, "%s", UTI_RefidToString(ref_id));
+ } else if (no_dns || csv_mode) {
+ snprintf(buf, size, "%s", UTI_IPToString(ip_addr));
+ } else {
+ DNS_IPAddress2Name(ip_addr, buf, size);
+ if (trunc_dns > 0 && strlen(buf) > trunc_dns) {
+ buf[trunc_dns - 1] = '>';
+ buf[trunc_dns] = '\0';
+ }
+ }
+}
+
+/* ================================================== */
+
+static int
+check_for_verbose_flag(char *line)
+{
+ if (!csv_mode && !strcmp(line, "-v"))
+ return 1;
+ return 0;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_sources(char *line)
+{
+ CMD_Request request;
+ CMD_Reply reply;
+ IPAddr ip_addr;
+ uint32_t i, mode, n_sources;
+ char name[50], mode_ch, state_ch;
+ int verbose;
+
+ /* Check whether to output verbose headers */
+ verbose = check_for_verbose_flag(line);
+
+ request.command = htons(REQ_N_SOURCES);
+ if (!request_reply(&request, &reply, RPY_N_SOURCES, 0))
+ return 0;
+
+ n_sources = ntohl(reply.data.n_sources.n_sources);
+ print_info_field("210 Number of sources = %lu\n", (unsigned long)n_sources);
+
+ if (verbose) {
+ printf("\n");
+ printf(" .-- Source mode '^' = server, '=' = peer, '#' = local clock.\n");
+ 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("|| Reachability register (octal) -. | xxxx = adjusted offset,\n");
+ printf("|| Log2(Polling interval) --. | | yyyy = measured offset,\n");
+ printf("|| \\ | | zzzz = estimated error.\n");
+ printf("|| | | \\\n");
+ }
+
+ print_header("MS Name/IP address Stratum Poll Reach LastRx Last sample ");
+
+ /* "MS NNNNNNNNNNNNNNNNNNNNNNNNNNN SS PP RRR RRRR SSSSSSS[SSSSSSS] +/- SSSSSS" */
+
+ for (i = 0; i < n_sources; i++) {
+ request.command = htons(REQ_SOURCE_DATA);
+ request.data.source_data.index = htonl(i);
+ if (!request_reply(&request, &reply, RPY_SOURCE_DATA, 0))
+ return 0;
+
+ mode = ntohs(reply.data.source_data.mode);
+ UTI_IPNetworkToHost(&reply.data.source_data.ip_addr, &ip_addr);
+ format_name(name, sizeof (name), 25,
+ mode == RPY_SD_MD_REF && ip_addr.family == IPADDR_INET4,
+ ip_addr.addr.in4, &ip_addr);
+
+ switch (mode) {
+ case RPY_SD_MD_CLIENT:
+ mode_ch = '^';
+ break;
+ case RPY_SD_MD_PEER:
+ mode_ch = '=';
+ break;
+ case RPY_SD_MD_REF:
+ mode_ch = '#';
+ break;
+ default:
+ mode_ch = ' ';
+ }
+
+ switch (ntohs(reply.data.source_data.state)) {
+ case RPY_SD_ST_SYNC:
+ state_ch = '*';
+ break;
+ case RPY_SD_ST_UNREACH:
+ state_ch = '?';
+ break;
+ case RPY_SD_ST_FALSETICKER:
+ state_ch = 'x';
+ break;
+ case RPY_SD_ST_JITTERY:
+ state_ch = '~';
+ break;
+ case RPY_SD_ST_CANDIDATE:
+ state_ch = '+';
+ break;
+ case RPY_SD_ST_OUTLIER:
+ state_ch = '-';
+ break;
+ default:
+ state_ch = ' ';
+ }
+
+ switch (ntohs(reply.data.source_data.flags)) {
+ default:
+ break;
+ }
+
+ print_report("%c%c %-27s %2d %2d %3o %I %+S[%+S] +/- %S\n",
+ mode_ch, state_ch, name,
+ ntohs(reply.data.source_data.stratum),
+ (int16_t)ntohs(reply.data.source_data.poll),
+ ntohs(reply.data.source_data.reachability),
+ (unsigned long)ntohl(reply.data.source_data.since_sample),
+ UTI_FloatNetworkToHost(reply.data.source_data.latest_meas),
+ UTI_FloatNetworkToHost(reply.data.source_data.orig_latest_meas),
+ UTI_FloatNetworkToHost(reply.data.source_data.latest_meas_err),
+ REPORT_END);
+ }
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_sourcestats(char *line)
+{
+ CMD_Request request;
+ CMD_Reply reply;
+ uint32_t i, n_sources;
+ int verbose = 0;
+ char name[50];
+ IPAddr ip_addr;
+
+ verbose = check_for_verbose_flag(line);
+
+ request.command = htons(REQ_N_SOURCES);
+ if (!request_reply(&request, &reply, RPY_N_SOURCES, 0))
+ return 0;
+
+ n_sources = ntohl(reply.data.n_sources.n_sources);
+ print_info_field("210 Number of sources = %lu\n", (unsigned long)n_sources);
+
+ if (verbose) {
+ printf(" .- Number of sample points in measurement set.\n");
+ printf(" / .- Number of residual runs with same sign.\n");
+ printf(" | / .- Length of measurement set (time).\n");
+ printf(" | | / .- Est. clock freq error (ppm).\n");
+ printf(" | | | / .- Est. error in freq.\n");
+ printf(" | | | | / .- Est. offset.\n");
+ printf(" | | | | | | On the -.\n");
+ printf(" | | | | | | samples. \\\n");
+ printf(" | | | | | | |\n");
+ }
+
+ print_header("Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev");
+
+ /* "NNNNNNNNNNNNNNNNNNNNNNNNN NP NR SSSS FFFFFFFFFF SSSSSSSSSS SSSSSSS SSSSSS" */
+
+ for (i = 0; i < n_sources; i++) {
+ request.command = htons(REQ_SOURCESTATS);
+ request.data.source_data.index = htonl(i);
+ if (!request_reply(&request, &reply, RPY_SOURCESTATS, 0))
+ return 0;
+
+ UTI_IPNetworkToHost(&reply.data.sourcestats.ip_addr, &ip_addr);
+ format_name(name, sizeof (name), 25, ip_addr.family == IPADDR_UNSPEC,
+ ntohl(reply.data.sourcestats.ref_id), &ip_addr);
+
+ print_report("%-25s %3U %3U %I %+P %P %+S %S\n",
+ name,
+ (unsigned long)ntohl(reply.data.sourcestats.n_samples),
+ (unsigned long)ntohl(reply.data.sourcestats.n_runs),
+ (unsigned long)ntohl(reply.data.sourcestats.span_seconds),
+ UTI_FloatNetworkToHost(reply.data.sourcestats.resid_freq_ppm),
+ UTI_FloatNetworkToHost(reply.data.sourcestats.skew_ppm),
+ UTI_FloatNetworkToHost(reply.data.sourcestats.est_offset),
+ UTI_FloatNetworkToHost(reply.data.sourcestats.sd),
+ REPORT_END);
+ }
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_tracking(char *line)
+{
+ CMD_Request request;
+ CMD_Reply reply;
+ IPAddr ip_addr;
+ uint32_t ref_id;
+ char name[50];
+ struct timespec ref_time;
+
+ request.command = htons(REQ_TRACKING);
+ if (!request_reply(&request, &reply, RPY_TRACKING, 0))
+ return 0;
+
+ ref_id = ntohl(reply.data.tracking.ref_id);
+
+ UTI_IPNetworkToHost(&reply.data.tracking.ip_addr, &ip_addr);
+ format_name(name, sizeof (name), sizeof (name),
+ ip_addr.family == IPADDR_UNSPEC, ref_id, &ip_addr);
+
+ UTI_TimespecNetworkToHost(&reply.data.tracking.ref_time, &ref_time);
+
+ print_report("Reference ID : %R (%s)\n"
+ "Stratum : %u\n"
+ "Ref time (UTC) : %T\n"
+ "System time : %.9O of NTP time\n"
+ "Last offset : %+.9f seconds\n"
+ "RMS offset : %.9f seconds\n"
+ "Frequency : %.3F\n"
+ "Residual freq : %+.3f ppm\n"
+ "Skew : %.3f ppm\n"
+ "Root delay : %.9f seconds\n"
+ "Root dispersion : %.9f seconds\n"
+ "Update interval : %.1f seconds\n"
+ "Leap status : %L\n",
+ (unsigned long)ref_id, name,
+ ntohs(reply.data.tracking.stratum),
+ &ref_time,
+ UTI_FloatNetworkToHost(reply.data.tracking.current_correction),
+ UTI_FloatNetworkToHost(reply.data.tracking.last_offset),
+ UTI_FloatNetworkToHost(reply.data.tracking.rms_offset),
+ UTI_FloatNetworkToHost(reply.data.tracking.freq_ppm),
+ UTI_FloatNetworkToHost(reply.data.tracking.resid_freq_ppm),
+ UTI_FloatNetworkToHost(reply.data.tracking.skew_ppm),
+ UTI_FloatNetworkToHost(reply.data.tracking.root_delay),
+ UTI_FloatNetworkToHost(reply.data.tracking.root_dispersion),
+ UTI_FloatNetworkToHost(reply.data.tracking.last_update_interval),
+ ntohs(reply.data.tracking.leap_status), REPORT_END);
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_ntpdata(char *line)
+{
+ CMD_Request request;
+ CMD_Reply reply;
+ IPAddr remote_addr, local_addr;
+ struct timespec ref_time;
+ uint32_t i, n_sources;
+ uint16_t mode;
+ int specified_addr;
+
+ if (*line) {
+ specified_addr = 1;
+ n_sources = 1;
+ } else {
+ specified_addr = 0;
+ request.command = htons(REQ_N_SOURCES);
+ if (!request_reply(&request, &reply, RPY_N_SOURCES, 0))
+ return 0;
+ n_sources = ntohl(reply.data.n_sources.n_sources);
+ }
+
+ for (i = 0; i < n_sources; i++) {
+ if (specified_addr) {
+ if (DNS_Name2IPAddress(line, &remote_addr, 1) != DNS_Success) {
+ LOG(LOGS_ERR, "Could not get address for hostname");
+ return 0;
+ }
+ } else {
+ request.command = htons(REQ_SOURCE_DATA);
+ request.data.source_data.index = htonl(i);
+ if (!request_reply(&request, &reply, RPY_SOURCE_DATA, 0))
+ return 0;
+
+ mode = ntohs(reply.data.source_data.mode);
+ if (mode != RPY_SD_MD_CLIENT && mode != RPY_SD_MD_PEER)
+ continue;
+
+ UTI_IPNetworkToHost(&reply.data.source_data.ip_addr, &remote_addr);
+ }
+
+ request.command = htons(REQ_NTP_DATA);
+ UTI_IPHostToNetwork(&remote_addr, &request.data.ntp_data.ip_addr);
+ if (!request_reply(&request, &reply, RPY_NTP_DATA, 0))
+ return 0;
+
+ UTI_IPNetworkToHost(&reply.data.ntp_data.remote_addr, &remote_addr);
+ UTI_IPNetworkToHost(&reply.data.ntp_data.local_addr, &local_addr);
+ UTI_TimespecNetworkToHost(&reply.data.ntp_data.ref_time, &ref_time);
+
+ if (!specified_addr && !csv_mode)
+ printf("\n");
+
+ print_report("Remote address : %s (%R)\n"
+ "Remote port : %u\n"
+ "Local address : %s (%R)\n"
+ "Leap status : %L\n"
+ "Version : %u\n"
+ "Mode : %M\n"
+ "Stratum : %u\n"
+ "Poll interval : %d (%.0f seconds)\n"
+ "Precision : %d (%.9f seconds)\n"
+ "Root delay : %.6f seconds\n"
+ "Root dispersion : %.6f seconds\n"
+ "Reference ID : %R (%s)\n"
+ "Reference time : %T\n"
+ "Offset : %+.9f seconds\n"
+ "Peer delay : %.9f seconds\n"
+ "Peer dispersion : %.9f seconds\n"
+ "Response time : %.9f seconds\n"
+ "Jitter asymmetry: %+.2f\n"
+ "NTP tests : %.3b %.3b %.4b\n"
+ "Interleaved : %B\n"
+ "Authenticated : %B\n"
+ "TX timestamping : %N\n"
+ "RX timestamping : %N\n"
+ "Total TX : %U\n"
+ "Total RX : %U\n"
+ "Total valid RX : %U\n",
+ UTI_IPToString(&remote_addr), (unsigned long)UTI_IPToRefid(&remote_addr),
+ ntohs(reply.data.ntp_data.remote_port),
+ UTI_IPToString(&local_addr), (unsigned long)UTI_IPToRefid(&local_addr),
+ reply.data.ntp_data.leap, reply.data.ntp_data.version,
+ reply.data.ntp_data.mode, reply.data.ntp_data.stratum,
+ reply.data.ntp_data.poll, UTI_Log2ToDouble(reply.data.ntp_data.poll),
+ reply.data.ntp_data.precision, UTI_Log2ToDouble(reply.data.ntp_data.precision),
+ UTI_FloatNetworkToHost(reply.data.ntp_data.root_delay),
+ UTI_FloatNetworkToHost(reply.data.ntp_data.root_dispersion),
+ (unsigned long)ntohl(reply.data.ntp_data.ref_id),
+ reply.data.ntp_data.stratum <= 1 ?
+ UTI_RefidToString(ntohl(reply.data.ntp_data.ref_id)) : "",
+ &ref_time,
+ UTI_FloatNetworkToHost(reply.data.ntp_data.offset),
+ UTI_FloatNetworkToHost(reply.data.ntp_data.peer_delay),
+ UTI_FloatNetworkToHost(reply.data.ntp_data.peer_dispersion),
+ UTI_FloatNetworkToHost(reply.data.ntp_data.response_time),
+ UTI_FloatNetworkToHost(reply.data.ntp_data.jitter_asymmetry),
+ ntohs(reply.data.ntp_data.flags) >> 7,
+ ntohs(reply.data.ntp_data.flags) >> 4,
+ ntohs(reply.data.ntp_data.flags),
+ ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_INTERLEAVED,
+ ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_AUTHENTICATED,
+ reply.data.ntp_data.tx_tss_char, reply.data.ntp_data.rx_tss_char,
+ (unsigned long)ntohl(reply.data.ntp_data.total_tx_count),
+ (unsigned long)ntohl(reply.data.ntp_data.total_rx_count),
+ (unsigned long)ntohl(reply.data.ntp_data.total_valid_count),
+ REPORT_END);
+ }
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_serverstats(char *line)
+{
+ CMD_Request request;
+ CMD_Reply reply;
+
+ request.command = htons(REQ_SERVER_STATS);
+ if (!request_reply(&request, &reply, RPY_SERVER_STATS, 0))
+ return 0;
+
+ print_report("NTP packets received : %U\n"
+ "NTP packets dropped : %U\n"
+ "Command packets received : %U\n"
+ "Command packets dropped : %U\n"
+ "Client log records dropped : %U\n",
+ (unsigned long)ntohl(reply.data.server_stats.ntp_hits),
+ (unsigned long)ntohl(reply.data.server_stats.ntp_drops),
+ (unsigned long)ntohl(reply.data.server_stats.cmd_hits),
+ (unsigned long)ntohl(reply.data.server_stats.cmd_drops),
+ (unsigned long)ntohl(reply.data.server_stats.log_drops),
+ REPORT_END);
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_smoothing(char *line)
+{
+ CMD_Request request;
+ CMD_Reply reply;
+ uint32_t flags;
+
+ request.command = htons(REQ_SMOOTHING);
+ if (!request_reply(&request, &reply, RPY_SMOOTHING, 0))
+ return 0;
+
+ flags = ntohl(reply.data.smoothing.flags);
+
+ print_report("Active : %B %s\n"
+ "Offset : %+.9f seconds\n"
+ "Frequency : %+.6f ppm\n"
+ "Wander : %+.6f ppm per second\n"
+ "Last update : %.1f seconds ago\n"
+ "Remaining time : %.1f seconds\n",
+ !!(flags & RPY_SMT_FLAG_ACTIVE),
+ flags & RPY_SMT_FLAG_LEAPONLY ? "(leap second only)" : "",
+ UTI_FloatNetworkToHost(reply.data.smoothing.offset),
+ UTI_FloatNetworkToHost(reply.data.smoothing.freq_ppm),
+ UTI_FloatNetworkToHost(reply.data.smoothing.wander_ppm),
+ UTI_FloatNetworkToHost(reply.data.smoothing.last_update_ago),
+ UTI_FloatNetworkToHost(reply.data.smoothing.remaining_time),
+ REPORT_END);
+
+ return 1;
+}
+
+/* ================================================== */
+
+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 {
+ LOG(LOGS_ERR, "Invalid syntax for smoothtime command");
+ return 0;
+ }
+
+ msg->command = htons(REQ_SMOOTHTIME);
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_rtcreport(char *line)
+{
+ CMD_Request request;
+ CMD_Reply reply;
+ struct timespec ref_time;
+
+ request.command = htons(REQ_RTCREPORT);
+ if (!request_reply(&request, &reply, RPY_RTC, 0))
+ return 0;
+
+ UTI_TimespecNetworkToHost(&reply.data.rtc.ref_time, &ref_time);
+
+ print_report("RTC ref time (UTC) : %T\n"
+ "Number of samples : %u\n"
+ "Number of runs : %u\n"
+ "Sample span period : %I\n"
+ "RTC is fast by : %12.6f seconds\n"
+ "RTC gains time at : %9.3f ppm\n",
+ &ref_time,
+ ntohs(reply.data.rtc.n_samples),
+ ntohs(reply.data.rtc.n_runs),
+ (unsigned long)ntohl(reply.data.rtc.span_seconds),
+ UTI_FloatNetworkToHost(reply.data.rtc.rtc_seconds_fast),
+ UTI_FloatNetworkToHost(reply.data.rtc.rtc_gain_rate_ppm),
+ REPORT_END);
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_clients(char *line)
+{
+ CMD_Request request;
+ CMD_Reply reply;
+ IPAddr ip;
+ uint32_t i, n_clients, next_index, n_indices;
+ RPY_ClientAccesses_Client *client;
+ char name[50];
+
+ next_index = 0;
+
+ print_header("Hostname NTP Drop Int IntL Last Cmd Drop Int Last");
+
+ while (1) {
+ request.command = htons(REQ_CLIENT_ACCESSES_BY_INDEX2);
+ request.data.client_accesses_by_index.first_index = htonl(next_index);
+ request.data.client_accesses_by_index.n_clients = htonl(MAX_CLIENT_ACCESSES);
+
+ if (!request_reply(&request, &reply, RPY_CLIENT_ACCESSES_BY_INDEX2, 0))
+ return 0;
+
+ n_clients = ntohl(reply.data.client_accesses_by_index.n_clients);
+ n_indices = ntohl(reply.data.client_accesses_by_index.n_indices);
+
+ for (i = 0; i < n_clients && i < MAX_CLIENT_ACCESSES; i++) {
+ client = &reply.data.client_accesses_by_index.clients[i];
+
+ UTI_IPNetworkToHost(&client->ip, &ip);
+
+ /* UNSPEC means the record could not be found in the daemon's tables.
+ We shouldn't ever generate this case, but ignore it if we do. */
+ if (ip.family == IPADDR_UNSPEC)
+ continue;
+
+ format_name(name, sizeof (name), 25, 0, 0, &ip);
+
+ print_report("%-25s %6U %5U %C %C %I %6U %5U %C %I\n",
+ name,
+ (unsigned long)ntohl(client->ntp_hits),
+ (unsigned long)ntohl(client->ntp_drops),
+ client->ntp_interval,
+ client->ntp_timeout_interval,
+ (unsigned long)ntohl(client->last_ntp_hit_ago),
+ (unsigned long)ntohl(client->cmd_hits),
+ (unsigned long)ntohl(client->cmd_drops),
+ client->cmd_interval,
+ (unsigned long)ntohl(client->last_cmd_hit_ago),
+ REPORT_END);
+ }
+
+ /* Set the next index to probe based on what the server tells us */
+ next_index = ntohl(reply.data.client_accesses_by_index.next_index);
+
+ if (next_index >= n_indices || n_clients < MAX_CLIENT_ACCESSES)
+ break;
+ }
+
+ return 1;
+}
+
+
+/* ================================================== */
+/* Process the manual list command */
+static int
+process_cmd_manual_list(const char *line)
+{
+ CMD_Request request;
+ CMD_Reply reply;
+ uint32_t i, n_samples;
+ RPY_ManualListSample *sample;
+ struct timespec when;
+
+ request.command = htons(REQ_MANUAL_LIST);
+ if (!request_reply(&request, &reply, RPY_MANUAL_LIST2, 0))
+ return 0;
+
+ n_samples = ntohl(reply.data.manual_list.n_samples);
+ print_info_field("210 n_samples = %lu\n", (unsigned long)n_samples);
+
+ print_header("# Date Time(UTC) Slewed Original Residual");
+
+ for (i = 0; i < n_samples && i < MAX_MANUAL_LIST_SAMPLES; i++) {
+ sample = &reply.data.manual_list.samples[i];
+ UTI_TimespecNetworkToHost(&sample->when, &when);
+
+ print_report("%2d %s %10.2f %10.2f %10.2f\n",
+ i, UTI_TimeToLogForm(when.tv_sec),
+ UTI_FloatNetworkToHost(sample->slewed_offset),
+ UTI_FloatNetworkToHost(sample->orig_offset),
+ UTI_FloatNetworkToHost(sample->residual),
+ REPORT_END);
+ }
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_manual_delete(CMD_Request *msg, const char *line)
+{
+ int index;
+
+ if (sscanf(line, "%d", &index) != 1) {
+ LOG(LOGS_ERR, "Bad syntax for manual delete command");
+ return 0;
+ }
+
+ msg->command = htons(REQ_MANUAL_DELETE);
+ msg->data.manual_delete.index = htonl(index);
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_settime(char *line)
+{
+ struct timespec ts;
+ time_t now, new_time;
+ CMD_Request request;
+ CMD_Reply reply;
+ double dfreq_ppm, new_afreq_ppm;
+ double offset;
+
+ now = time(NULL);
+ new_time = get_date(line, &now);
+
+ if (new_time == -1) {
+ printf("510 - Could not parse date string\n");
+ } else {
+ ts.tv_sec = new_time;
+ ts.tv_nsec = 0;
+ UTI_TimespecHostToNetwork(&ts, &request.data.settime.ts);
+ request.command = htons(REQ_SETTIME);
+ if (request_reply(&request, &reply, RPY_MANUAL_TIMESTAMP2, 1)) {
+ offset = UTI_FloatNetworkToHost(reply.data.manual_timestamp.offset);
+ dfreq_ppm = UTI_FloatNetworkToHost(reply.data.manual_timestamp.dfreq_ppm);
+ new_afreq_ppm = UTI_FloatNetworkToHost(reply.data.manual_timestamp.new_afreq_ppm);
+ printf("Clock was %.2f seconds fast. Frequency change = %.2fppm, new frequency = %.2fppm\n",
+ offset, dfreq_ppm, new_afreq_ppm);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* ================================================== */
+
+static void
+process_cmd_rekey(CMD_Request *msg, char *line)
+{
+ msg->command = htons(REQ_REKEY);
+}
+
+/* ================================================== */
+
+static int
+process_cmd_makestep(CMD_Request *msg, char *line)
+{
+ int limit;
+ double threshold;
+
+ if (*line) {
+ if (sscanf(line, "%lf %d", &threshold, &limit) != 2) {
+ LOG(LOGS_ERR, "Bad syntax for makestep command");
+ 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;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_activity(const char *line)
+{
+ CMD_Request request;
+ CMD_Reply reply;
+
+ request.command = htons(REQ_ACTIVITY);
+ if (!request_reply(&request, &reply, RPY_ACTIVITY, 0))
+ return 0;
+
+ print_info_field("200 OK\n");
+
+ print_report("%U sources online\n"
+ "%U sources offline\n"
+ "%U sources doing burst (return to online)\n"
+ "%U sources doing burst (return to offline)\n"
+ "%U sources with unknown address\n",
+ (unsigned long)ntohl(reply.data.activity.online),
+ (unsigned long)ntohl(reply.data.activity.offline),
+ (unsigned long)ntohl(reply.data.activity.burst_online),
+ (unsigned long)ntohl(reply.data.activity.burst_offline),
+ (unsigned long)ntohl(reply.data.activity.unresolved),
+ REPORT_END);
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_reselectdist(CMD_Request *msg, char *line)
+{
+ double dist;
+ int ok;
+ msg->command = htons(REQ_RESELECTDISTANCE);
+ if (sscanf(line, "%lf", &dist) == 1) {
+ msg->data.reselect_distance.distance = UTI_FloatHostToNetwork(dist);
+ ok = 1;
+ } else {
+ ok = 0;
+ }
+ return ok;
+}
+
+/* ================================================== */
+
+static void
+process_cmd_reselect(CMD_Request *msg, char *line)
+{
+ msg->command = htons(REQ_RESELECT);
+}
+
+/* ================================================== */
+
+static void
+process_cmd_refresh(CMD_Request *msg, char *line)
+{
+ msg->command = htons(REQ_REFRESH);
+}
+
+/* ================================================== */
+
+static void
+process_cmd_shutdown(CMD_Request *msg, char *line)
+{
+ msg->command = htons(REQ_SHUTDOWN);
+}
+
+/* ================================================== */
+
+static int
+process_cmd_waitsync(char *line)
+{
+ CMD_Request request;
+ CMD_Reply reply;
+ IPAddr ip_addr;
+ uint32_t ref_id;
+ double correction, skew_ppm, max_correction, max_skew_ppm, interval;
+ int ret = 0, max_tries, i;
+ struct timeval timeout;
+
+ max_tries = 0;
+ max_correction = 0.0;
+ max_skew_ppm = 0.0;
+ interval = 10.0;
+
+ if (sscanf(line, "%d %lf %lf %lf", &max_tries, &max_correction, &max_skew_ppm, &interval))
+ ;
+
+ /* Don't allow shorter interval than 0.1 seconds */
+ if (interval < 0.1)
+ interval = 0.1;
+
+ request.command = htons(REQ_TRACKING);
+
+ for (i = 1; ; i++) {
+ if (request_reply(&request, &reply, RPY_TRACKING, 0)) {
+ ref_id = ntohl(reply.data.tracking.ref_id);
+ UTI_IPNetworkToHost(&reply.data.tracking.ip_addr, &ip_addr);
+
+ correction = UTI_FloatNetworkToHost(reply.data.tracking.current_correction);
+ correction = fabs(correction);
+ skew_ppm = UTI_FloatNetworkToHost(reply.data.tracking.skew_ppm);
+
+ print_report("try: %d, refid: %R, correction: %.9f, skew: %.3f\n",
+ i, (unsigned long)ref_id, correction, skew_ppm, REPORT_END);
+
+ if ((ip_addr.family != IPADDR_UNSPEC ||
+ (ref_id != 0 && ref_id != 0x7f7f0101L /* LOCAL refid */)) &&
+ (max_correction == 0.0 || correction <= max_correction) &&
+ (max_skew_ppm == 0.0 || skew_ppm <= max_skew_ppm)) {
+ ret = 1;
+ }
+ }
+
+ if (!ret && (!max_tries || i < max_tries) && !quit) {
+ UTI_DoubleToTimeval(interval, &timeout);
+ if (select(0, NULL, NULL, NULL, &timeout))
+ break;
+ } else {
+ break;
+ }
+ }
+ return ret;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_dns(const char *line)
+{
+ if (!strcmp(line, "-46")) {
+ DNS_SetAddressFamily(IPADDR_UNSPEC);
+ } else if (!strcmp(line, "-4")) {
+ DNS_SetAddressFamily(IPADDR_INET4);
+ } else if (!strcmp(line, "-6")) {
+ DNS_SetAddressFamily(IPADDR_INET6);
+ } else if (!strcmp(line, "-n")) {
+ no_dns = 1;
+ } else if (!strcmp(line, "+n")) {
+ no_dns = 0;
+ } else {
+ LOG(LOGS_ERR, "Unrecognized dns command");
+ return 0;
+ }
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_timeout(const char *line)
+{
+ int timeout;
+
+ timeout = atoi(line);
+ if (timeout < 100) {
+ LOG(LOGS_ERR, "Timeout %d is too short", timeout);
+ return 0;
+ }
+ initial_timeout = timeout;
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_retries(const char *line)
+{
+ int retries;
+
+ retries = atoi(line);
+ if (retries < 0 || retries > 30) {
+ LOG(LOGS_ERR, "Invalid maximum number of retries");
+ return 0;
+ }
+ max_retries = retries;
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_cmd_keygen(char *line)
+{
+ char hash_name[17];
+ unsigned char key[512];
+ unsigned int i, length, id = 1, bits = 160;
+
+#ifdef FEAT_SECHASH
+ snprintf(hash_name, sizeof (hash_name), "SHA1");
+#else
+ snprintf(hash_name, sizeof (hash_name), "MD5");
+#endif
+
+ if (sscanf(line, "%u %16s %u", &id, hash_name, &bits))
+ ;
+
+ length = CLAMP(10, (bits + 7) / 8, sizeof (key));
+ if (HSH_GetHashId(hash_name) < 0) {
+ LOG(LOGS_ERR, "Unknown hash function %s", hash_name);
+ return 0;
+ }
+
+ UTI_GetRandomBytesUrandom(key, length);
+
+ printf("%u %s HEX:", id, hash_name);
+ for (i = 0; i < length; i++)
+ printf("%02hhX", key[i]);
+ printf("\n");
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+process_line(char *line)
+{
+ char *command;
+ int do_normal_submit;
+ int ret;
+ CMD_Request tx_message;
+ CMD_Reply rx_message;
+
+ ret = 0;
+
+ do_normal_submit = 1;
+
+ CPS_NormalizeLine(line);
+
+ if (!*line) {
+ fflush(stderr);
+ fflush(stdout);
+ return 1;
+ };
+
+ command = line;
+ line = CPS_SplitWord(line);
+
+ if (!strcmp(command, "accheck")) {
+ do_normal_submit = process_cmd_accheck(&tx_message, line);
+ } else if (!strcmp(command, "activity")) {
+ do_normal_submit = 0;
+ ret = process_cmd_activity(line);
+ } else if (!strcmp(command, "add") && !strncmp(line, "peer", 4)) {
+ do_normal_submit = process_cmd_add_peer(&tx_message, CPS_SplitWord(line));
+ } else if (!strcmp(command, "add") && !strncmp(line, "server", 6)) {
+ do_normal_submit = process_cmd_add_server(&tx_message, CPS_SplitWord(line));
+ } else if (!strcmp(command, "allow")) {
+ if (!strncmp(line, "all", 3)) {
+ do_normal_submit = process_cmd_allowall(&tx_message, CPS_SplitWord(line));
+ } else {
+ do_normal_submit = process_cmd_allow(&tx_message, line);
+ }
+ } else if (!strcmp(command, "burst")) {
+ do_normal_submit = process_cmd_burst(&tx_message, line);
+ } else if (!strcmp(command, "clients")) {
+ ret = process_cmd_clients(line);
+ do_normal_submit = 0;
+ } else if (!strcmp(command, "cmdaccheck")) {
+ do_normal_submit = process_cmd_cmdaccheck(&tx_message, line);
+ } else if (!strcmp(command, "cmdallow")) {
+ if (!strncmp(line, "all", 3)) {
+ do_normal_submit = process_cmd_cmdallowall(&tx_message, CPS_SplitWord(line));
+ } else {
+ do_normal_submit = process_cmd_cmdallow(&tx_message, line);
+ }
+ } else if (!strcmp(command, "cmddeny")) {
+ if (!strncmp(line, "all", 3)) {
+ line = CPS_SplitWord(line);
+ do_normal_submit = process_cmd_cmddenyall(&tx_message, line);
+ } else {
+ do_normal_submit = process_cmd_cmddeny(&tx_message, line);
+ }
+ } else if (!strcmp(command, "cyclelogs")) {
+ process_cmd_cyclelogs(&tx_message, line);
+ } else if (!strcmp(command, "delete")) {
+ do_normal_submit = process_cmd_delete(&tx_message, line);
+ } else if (!strcmp(command, "deny")) {
+ if (!strncmp(line, "all", 3)) {
+ do_normal_submit = process_cmd_denyall(&tx_message, CPS_SplitWord(line));
+ } else {
+ do_normal_submit = process_cmd_deny(&tx_message, line);
+ }
+ } else if (!strcmp(command, "dfreq")) {
+ process_cmd_dfreq(&tx_message, line);
+ } else if (!strcmp(command, "dns")) {
+ ret = process_cmd_dns(line);
+ do_normal_submit = 0;
+ } else if (!strcmp(command, "doffset")) {
+ process_cmd_doffset(&tx_message, line);
+ } else if (!strcmp(command, "dump")) {
+ process_cmd_dump(&tx_message, line);
+ } else if (!strcmp(command, "exit")) {
+ do_normal_submit = 0;
+ quit = 1;
+ ret = 1;
+ } else if (!strcmp(command, "help")) {
+ do_normal_submit = 0;
+ give_help();
+ ret = 1;
+ } else if (!strcmp(command, "keygen")) {
+ ret = process_cmd_keygen(line);
+ do_normal_submit = 0;
+ } else if (!strcmp(command, "local")) {
+ do_normal_submit = process_cmd_local(&tx_message, line);
+ } else if (!strcmp(command, "makestep")) {
+ do_normal_submit = process_cmd_makestep(&tx_message, line);
+ } else if (!strcmp(command, "manual")) {
+ if (!strncmp(line, "list", 4)) {
+ do_normal_submit = 0;
+ ret = process_cmd_manual_list(CPS_SplitWord(line));
+ } else if (!strncmp(line, "delete", 6)) {
+ do_normal_submit = process_cmd_manual_delete(&tx_message, CPS_SplitWord(line));
+ } else {
+ do_normal_submit = process_cmd_manual(&tx_message, line);
+ }
+ } else if (!strcmp(command, "maxdelay")) {
+ do_normal_submit = process_cmd_maxdelay(&tx_message, line);
+ } else if (!strcmp(command, "maxdelaydevratio")) {
+ do_normal_submit = process_cmd_maxdelaydevratio(&tx_message, line);
+ } else if (!strcmp(command, "maxdelayratio")) {
+ do_normal_submit = process_cmd_maxdelayratio(&tx_message, line);
+ } else if (!strcmp(command, "maxpoll")) {
+ do_normal_submit = process_cmd_maxpoll(&tx_message, line);
+ } else if (!strcmp(command, "maxupdateskew")) {
+ do_normal_submit = process_cmd_maxupdateskew(&tx_message, line);
+ } else if (!strcmp(command, "minpoll")) {
+ do_normal_submit = process_cmd_minpoll(&tx_message, line);
+ } else if (!strcmp(command, "minstratum")) {
+ do_normal_submit = process_cmd_minstratum(&tx_message, line);
+ } else if (!strcmp(command, "ntpdata")) {
+ do_normal_submit = 0;
+ ret = process_cmd_ntpdata(line);
+ } else if (!strcmp(command, "offline")) {
+ do_normal_submit = process_cmd_offline(&tx_message, line);
+ } else if (!strcmp(command, "online")) {
+ do_normal_submit = process_cmd_online(&tx_message, line);
+ } else if (!strcmp(command, "onoffline")) {
+ process_cmd_onoffline(&tx_message, line);
+ } else if (!strcmp(command, "polltarget")) {
+ do_normal_submit = process_cmd_polltarget(&tx_message, line);
+ } else if (!strcmp(command, "quit")) {
+ do_normal_submit = 0;
+ quit = 1;
+ ret = 1;
+ } else if (!strcmp(command, "refresh")) {
+ process_cmd_refresh(&tx_message, line);
+ } else if (!strcmp(command, "rekey")) {
+ process_cmd_rekey(&tx_message, line);
+ } else if (!strcmp(command, "reselect")) {
+ process_cmd_reselect(&tx_message, line);
+ } else if (!strcmp(command, "reselectdist")) {
+ do_normal_submit = process_cmd_reselectdist(&tx_message, line);
+ } else if (!strcmp(command, "retries")) {
+ ret = process_cmd_retries(line);
+ do_normal_submit = 0;
+ } else if (!strcmp(command, "rtcdata")) {
+ do_normal_submit = 0;
+ ret = process_cmd_rtcreport(line);
+ } else if (!strcmp(command, "serverstats")) {
+ do_normal_submit = 0;
+ ret = process_cmd_serverstats(line);
+ } else if (!strcmp(command, "settime")) {
+ do_normal_submit = 0;
+ ret = process_cmd_settime(line);
+ } else if (!strcmp(command, "shutdown")) {
+ process_cmd_shutdown(&tx_message, 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);
+ } else if (!strcmp(command, "sourcestats")) {
+ do_normal_submit = 0;
+ ret = process_cmd_sourcestats(line);
+ } else if (!strcmp(command, "timeout")) {
+ ret = process_cmd_timeout(line);
+ do_normal_submit = 0;
+ } else if (!strcmp(command, "tracking")) {
+ ret = process_cmd_tracking(line);
+ do_normal_submit = 0;
+ } else if (!strcmp(command, "trimrtc")) {
+ process_cmd_trimrtc(&tx_message, line);
+ } else if (!strcmp(command, "waitsync")) {
+ ret = process_cmd_waitsync(line);
+ do_normal_submit = 0;
+ } else if (!strcmp(command, "writertc")) {
+ process_cmd_writertc(&tx_message, line);
+ } else if (!strcmp(command, "authhash") ||
+ !strcmp(command, "password")) {
+ /* Warn, but don't return error to not break scripts */
+ LOG(LOGS_WARN, "Authentication is no longer supported");
+ do_normal_submit = 0;
+ ret = 1;
+ } else {
+ LOG(LOGS_ERR, "Unrecognized command");
+ do_normal_submit = 0;
+ }
+
+ if (do_normal_submit) {
+ ret = request_reply(&tx_message, &rx_message, RPY_NULL, 1);
+ }
+ fflush(stderr);
+ fflush(stdout);
+ return ret;
+}
+
+/* ================================================== */
+
+static int
+process_args(int argc, char **argv, int multi)
+{
+ int total_length, i, ret = 0;
+ char *line;
+
+ total_length = 0;
+ for(i=0; i<argc; i++) {
+ total_length += strlen(argv[i]) + 1;
+ }
+
+ line = (char *) Malloc((2 + total_length) * sizeof(char));
+
+ for (i = 0; i < argc; i++) {
+ line[0] = '\0';
+ if (multi) {
+ strcat(line, argv[i]);
+ } else {
+ for (; i < argc; i++) {
+ strcat(line, argv[i]);
+ if (i + 1 < argc)
+ strcat(line, " ");
+ }
+ }
+
+ ret = process_line(line);
+ if (!ret || quit)
+ break;
+ }
+
+ Free(line);
+
+ return ret;
+}
+
+/* ================================================== */
+
+static void
+signal_handler(int signum)
+{
+ quit = 1;
+}
+
+/* ================================================== */
+
+static void
+display_gpl(void)
+{
+ printf("chrony version %s\n"
+ "Copyright (C) 1997-2003, 2007, 2009-2018 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",
+ CHRONY_VERSION);
+}
+
+/* ================================================== */
+
+static void
+print_help(const char *progname)
+{
+ printf("Usage: %s [-h HOST] [-p PORT] [-n] [-c] [-d] [-4|-6] [-m] [COMMAND]\n",
+ progname);
+}
+
+/* ================================================== */
+
+static void
+print_version(void)
+{
+ printf("chronyc (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYC_FEATURES);
+}
+
+/* ================================================== */
+
+int
+main(int argc, char **argv)
+{
+ char *line;
+ const char *progname = argv[0];
+ const char *hostnames = NULL;
+ int opt, ret = 1, multi = 0, family = IPADDR_UNSPEC;
+ int port = DEFAULT_CANDM_PORT;
+
+ /* Parse (undocumented) long command-line options */
+ for (optind = 1; optind < argc; optind++) {
+ if (!strcmp("--help", argv[optind])) {
+ print_help(progname);
+ return 0;
+ } else if (!strcmp("--version", argv[optind])) {
+ print_version();
+ return 0;
+ }
+ }
+
+ optind = 1;
+
+ /* Parse short command-line options */
+ while ((opt = getopt(argc, argv, "+46acdf:h:mnp:v")) != -1) {
+ switch (opt) {
+ case '4':
+ case '6':
+ family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6;
+ break;
+ case 'a':
+ case 'f':
+ /* For compatibility only */
+ break;
+ case 'c':
+ csv_mode = 1;
+ break;
+ case 'd':
+ log_debug_enabled = 1;
+ break;
+ case 'h':
+ hostnames = optarg;
+ break;
+ case 'm':
+ multi = 1;
+ break;
+ case 'n':
+ no_dns = 1;
+ break;
+ case 'p':
+ port = atoi(optarg);
+ break;
+ case 'v':
+ print_version();
+ return 0;
+ default:
+ print_help(progname);
+ return 1;
+ }
+ }
+
+ if (isatty(0) && isatty(1) && isatty(2)) {
+ on_terminal = 1;
+ }
+
+ if (on_terminal && optind == argc) {
+ display_gpl();
+ }
+
+ DNS_SetAddressFamily(family);
+
+ if (!hostnames) {
+ hostnames = DEFAULT_COMMAND_SOCKET",127.0.0.1,::1";
+ }
+
+ UTI_SetQuitSignalsHandler(signal_handler, 0);
+
+ sockaddrs = get_sockaddrs(hostnames, port);
+
+ if (!open_io())
+ LOG_FATAL("Could not open connection to daemon");
+
+ if (optind < argc) {
+ ret = process_args(argc - optind, argv + optind, multi);
+ } else {
+ do {
+ line = read_line();
+ if (line && !quit) {
+ ret = process_line(line);
+ }else {
+ /* supply the final '\n' when user exits via ^D */
+ if( on_terminal ) printf("\n");
+ }
+ } while (line && !quit);
+ }
+
+ close_io();
+
+ ARR_DestroyInstance(sockaddrs);
+
+ return !ret;
+}
+
+
diff --git a/clientlog.c b/clientlog.c
new file mode 100644
index 0000000..86962a7
--- /dev/null
+++ b/clientlog.c
@@ -0,0 +1,695 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow 1997-2003
+ * Copyright (C) Miroslav Lichvar 2009, 2015-2017
+ *
+ * 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 keeps a count of the number of successful accesses by
+ clients, and the times of the last accesses.
+
+ This can be used for status reporting, and (in the case of a
+ server), if it needs to know which clients have made use of its data
+ recently.
+
+ */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "array.h"
+#include "clientlog.h"
+#include "conf.h"
+#include "memory.h"
+#include "ntp.h"
+#include "reports.h"
+#include "util.h"
+#include "logging.h"
+
+typedef struct {
+ IPAddr ip_addr;
+ uint32_t last_ntp_hit;
+ uint32_t last_cmd_hit;
+ uint32_t ntp_hits;
+ uint32_t cmd_hits;
+ uint16_t ntp_drops;
+ uint16_t cmd_drops;
+ uint16_t ntp_tokens;
+ uint16_t cmd_tokens;
+ int8_t ntp_rate;
+ int8_t cmd_rate;
+ int8_t ntp_timeout_rate;
+ uint8_t flags;
+ NTP_int64 ntp_rx_ts;
+ NTP_int64 ntp_tx_ts;
+} Record;
+
+/* Hash table of records, there is a fixed number of records per slot */
+static ARR_Instance records;
+
+#define SLOT_BITS 4
+
+/* Number of records in one slot of the hash table */
+#define SLOT_SIZE (1U << SLOT_BITS)
+
+/* Minimum number of slots */
+#define MIN_SLOTS 1
+
+/* Maximum number of slots, this is a hard limit */
+#define MAX_SLOTS (1U << (24 - SLOT_BITS))
+
+/* Number of slots in the hash table */
+static unsigned int slots;
+
+/* Maximum number of slots given memory allocation limit */
+static unsigned int max_slots;
+
+/* Times of last hits are saved as 32-bit fixed point values */
+#define TS_FRAC 4
+#define INVALID_TS 0
+
+/* Static offset included in conversion to the fixed-point timestamps to
+ randomise their alignment */
+static uint32_t ts_offset;
+
+/* Request rates are saved in the record as 8-bit scaled log2 values */
+#define RATE_SCALE 4
+#define MIN_RATE (-14 * RATE_SCALE)
+#define INVALID_RATE -128
+
+/* Response rates are controlled by token buckets. The capacity and
+ number of tokens spent on response are determined from configured
+ minimum inverval between responses (in log2) and burst length. */
+
+#define MIN_LIMIT_INTERVAL (-15 - TS_FRAC)
+#define MAX_LIMIT_INTERVAL 12
+#define MIN_LIMIT_BURST 1
+#define MAX_LIMIT_BURST 255
+
+static uint16_t max_ntp_tokens;
+static uint16_t max_cmd_tokens;
+static uint16_t ntp_tokens_per_packet;
+static uint16_t cmd_tokens_per_packet;
+
+/* Reduction of token rates to avoid overflow of 16-bit counters. Negative
+ shift is used for coarse limiting with intervals shorter than -TS_FRAC. */
+static int ntp_token_shift;
+static int cmd_token_shift;
+
+/* Rates at which responses are randomly allowed (in log2) when the
+ buckets don't have enough tokens. This is necessary in order to
+ prevent an attacker sending requests with spoofed source address
+ from blocking responses to the address completely. */
+
+#define MIN_LEAK_RATE 1
+#define MAX_LEAK_RATE 4
+
+static int ntp_leak_rate;
+static int cmd_leak_rate;
+
+/* Flag indicating whether the last response was dropped */
+#define FLAG_NTP_DROPPED 0x1
+
+/* NTP limit interval in log2 */
+static int ntp_limit_interval;
+
+/* Flag indicating whether facility is turned on or not */
+static int active;
+
+/* Global statistics */
+static uint32_t total_ntp_hits;
+static uint32_t total_cmd_hits;
+static uint32_t total_ntp_drops;
+static uint32_t total_cmd_drops;
+static uint32_t total_record_drops;
+
+#define NSEC_PER_SEC 1000000000U
+
+/* ================================================== */
+
+static int expand_hashtable(void);
+
+/* ================================================== */
+
+static int
+compare_ts(uint32_t x, uint32_t y)
+{
+ if (x == y)
+ return 0;
+ if (y == INVALID_TS)
+ return 1;
+ return (int32_t)(x - y) > 0 ? 1 : -1;
+}
+
+/* ================================================== */
+
+static Record *
+get_record(IPAddr *ip)
+{
+ unsigned int first, i;
+ time_t last_hit, oldest_hit = 0;
+ Record *record, *oldest_record;
+
+ if (!active || (ip->family != IPADDR_INET4 && ip->family != IPADDR_INET6))
+ return NULL;
+
+ while (1) {
+ /* Get index of the first record in the slot */
+ first = UTI_IPToHash(ip) % slots * SLOT_SIZE;
+
+ for (i = 0, oldest_record = NULL; i < SLOT_SIZE; i++) {
+ record = ARR_GetElement(records, first + i);
+
+ if (!UTI_CompareIPs(ip, &record->ip_addr, NULL))
+ return record;
+
+ if (record->ip_addr.family == IPADDR_UNSPEC)
+ break;
+
+ last_hit = compare_ts(record->last_ntp_hit, record->last_cmd_hit) > 0 ?
+ record->last_ntp_hit : record->last_cmd_hit;
+
+ if (!oldest_record || compare_ts(oldest_hit, last_hit) > 0 ||
+ (oldest_hit == last_hit && record->ntp_hits + record->cmd_hits <
+ oldest_record->ntp_hits + oldest_record->cmd_hits)) {
+ oldest_record = record;
+ oldest_hit = last_hit;
+ }
+ }
+
+ /* If the slot still has an empty record, use it */
+ if (record->ip_addr.family == IPADDR_UNSPEC)
+ break;
+
+ /* Resize the table if possible and try again as the new slot may
+ have some empty records */
+ if (expand_hashtable())
+ continue;
+
+ /* There is no other option, replace the oldest record */
+ record = oldest_record;
+ total_record_drops++;
+ break;
+ }
+
+ record->ip_addr = *ip;
+ record->last_ntp_hit = record->last_cmd_hit = INVALID_TS;
+ record->ntp_hits = record->cmd_hits = 0;
+ record->ntp_drops = record->cmd_drops = 0;
+ record->ntp_tokens = max_ntp_tokens;
+ record->cmd_tokens = max_cmd_tokens;
+ record->ntp_rate = record->cmd_rate = INVALID_RATE;
+ record->ntp_timeout_rate = INVALID_RATE;
+ record->flags = 0;
+ UTI_ZeroNtp64(&record->ntp_rx_ts);
+ UTI_ZeroNtp64(&record->ntp_tx_ts);
+
+ return record;
+}
+
+/* ================================================== */
+
+static int
+expand_hashtable(void)
+{
+ ARR_Instance old_records;
+ Record *old_record, *new_record;
+ unsigned int i;
+
+ old_records = records;
+
+ if (2 * slots > max_slots)
+ return 0;
+
+ records = ARR_CreateInstance(sizeof (Record));
+
+ slots = MAX(MIN_SLOTS, 2 * slots);
+ assert(slots <= max_slots);
+
+ ARR_SetSize(records, slots * SLOT_SIZE);
+
+ /* Mark all new records as empty */
+ for (i = 0; i < slots * SLOT_SIZE; i++) {
+ new_record = ARR_GetElement(records, i);
+ new_record->ip_addr.family = IPADDR_UNSPEC;
+ }
+
+ if (!old_records)
+ return 1;
+
+ /* Copy old records to the new hash table */
+ for (i = 0; i < ARR_GetSize(old_records); i++) {
+ old_record = ARR_GetElement(old_records, i);
+ if (old_record->ip_addr.family == IPADDR_UNSPEC)
+ continue;
+
+ new_record = get_record(&old_record->ip_addr);
+
+ assert(new_record);
+ *new_record = *old_record;
+ }
+
+ ARR_DestroyInstance(old_records);
+
+ return 1;
+}
+
+/* ================================================== */
+
+static void
+set_bucket_params(int interval, int burst, uint16_t *max_tokens,
+ uint16_t *tokens_per_packet, int *token_shift)
+{
+ interval = CLAMP(MIN_LIMIT_INTERVAL, interval, MAX_LIMIT_INTERVAL);
+ burst = CLAMP(MIN_LIMIT_BURST, burst, MAX_LIMIT_BURST);
+
+ if (interval >= -TS_FRAC) {
+ /* Find the smallest shift with which the maximum number fits in 16 bits */
+ for (*token_shift = 0; *token_shift < interval + TS_FRAC; (*token_shift)++) {
+ if (burst << (TS_FRAC + interval - *token_shift) < 1U << 16)
+ break;
+ }
+ } else {
+ /* Coarse rate limiting */
+ *token_shift = interval + TS_FRAC;
+ *tokens_per_packet = 1;
+ burst = MAX(1U << -*token_shift, burst);
+ }
+
+ *tokens_per_packet = 1U << (TS_FRAC + interval - *token_shift);
+ *max_tokens = *tokens_per_packet * burst;
+
+ DEBUG_LOG("Tokens max %d packet %d shift %d",
+ *max_tokens, *tokens_per_packet, *token_shift);
+}
+
+/* ================================================== */
+
+void
+CLG_Initialise(void)
+{
+ int interval, burst, leak_rate;
+
+ max_ntp_tokens = max_cmd_tokens = 0;
+ ntp_tokens_per_packet = cmd_tokens_per_packet = 0;
+ ntp_token_shift = cmd_token_shift = 0;
+ ntp_leak_rate = cmd_leak_rate = 0;
+ ntp_limit_interval = MIN_LIMIT_INTERVAL;
+
+ if (CNF_GetNTPRateLimit(&interval, &burst, &leak_rate)) {
+ set_bucket_params(interval, burst, &max_ntp_tokens, &ntp_tokens_per_packet,
+ &ntp_token_shift);
+ ntp_leak_rate = CLAMP(MIN_LEAK_RATE, leak_rate, MAX_LEAK_RATE);
+ ntp_limit_interval = CLAMP(MIN_LIMIT_INTERVAL, interval, MAX_LIMIT_INTERVAL);
+ }
+
+ if (CNF_GetCommandRateLimit(&interval, &burst, &leak_rate)) {
+ set_bucket_params(interval, burst, &max_cmd_tokens, &cmd_tokens_per_packet,
+ &cmd_token_shift);
+ cmd_leak_rate = CLAMP(MIN_LEAK_RATE, leak_rate, MAX_LEAK_RATE);
+ }
+
+ active = !CNF_GetNoClientLog();
+ if (!active) {
+ if (ntp_leak_rate || cmd_leak_rate)
+ LOG_FATAL("ratelimit cannot be used with noclientlog");
+ return;
+ }
+
+ /* Calculate the maximum number of slots that can be allocated in the
+ configured memory limit. Take into account expanding of the hash
+ table where two copies exist at the same time. */
+ max_slots = CNF_GetClientLogLimit() / (sizeof (Record) * SLOT_SIZE * 3 / 2);
+ max_slots = CLAMP(MIN_SLOTS, max_slots, MAX_SLOTS);
+
+ slots = 0;
+ records = NULL;
+
+ expand_hashtable();
+
+ UTI_GetRandomBytes(&ts_offset, sizeof (ts_offset));
+ ts_offset %= NSEC_PER_SEC / (1U << TS_FRAC);
+}
+
+/* ================================================== */
+
+void
+CLG_Finalise(void)
+{
+ if (!active)
+ return;
+
+ ARR_DestroyInstance(records);
+}
+
+/* ================================================== */
+
+static uint32_t
+get_ts_from_timespec(struct timespec *ts)
+{
+ uint32_t sec = ts->tv_sec, nsec = ts->tv_nsec;
+
+ nsec += ts_offset;
+ if (nsec >= NSEC_PER_SEC) {
+ nsec -= NSEC_PER_SEC;
+ sec++;
+ }
+
+ /* This is fast and accurate enough */
+ return sec << TS_FRAC | (140740U * (nsec >> 15)) >> (32 - TS_FRAC);
+}
+
+/* ================================================== */
+
+static void
+update_record(struct timespec *now, uint32_t *last_hit, uint32_t *hits,
+ uint16_t *tokens, uint32_t max_tokens, int token_shift, int8_t *rate)
+{
+ uint32_t interval, now_ts, prev_hit, new_tokens;
+ int interval2;
+
+ now_ts = get_ts_from_timespec(now);
+
+ prev_hit = *last_hit;
+ *last_hit = now_ts;
+ (*hits)++;
+
+ interval = now_ts - prev_hit;
+
+ if (prev_hit == INVALID_TS || (int32_t)interval < 0)
+ return;
+
+ if (token_shift >= 0)
+ new_tokens = (now_ts >> token_shift) - (prev_hit >> token_shift);
+ else if (now_ts - prev_hit > max_tokens)
+ new_tokens = max_tokens;
+ else
+ new_tokens = (now_ts - prev_hit) << -token_shift;
+ *tokens = MIN(*tokens + new_tokens, max_tokens);
+
+ /* Convert the interval to scaled and rounded log2 */
+ if (interval) {
+ interval += interval >> 1;
+ for (interval2 = -RATE_SCALE * TS_FRAC; interval2 < -MIN_RATE;
+ interval2 += RATE_SCALE) {
+ if (interval <= 1)
+ break;
+ interval >>= 1;
+ }
+ } else {
+ interval2 = -RATE_SCALE * (TS_FRAC + 1);
+ }
+
+ /* Update the rate in a rough approximation of exponential moving average */
+ if (*rate == INVALID_RATE) {
+ *rate = -interval2;
+ } else {
+ if (*rate < -interval2) {
+ (*rate)++;
+ } else if (*rate > -interval2) {
+ if (*rate > RATE_SCALE * 5 / 2 - interval2)
+ *rate = RATE_SCALE * 5 / 2 - interval2;
+ else
+ *rate = (*rate - interval2 - 1) / 2;
+ }
+ }
+}
+
+/* ================================================== */
+
+static int
+get_index(Record *record)
+{
+ return record - (Record *)ARR_GetElements(records);
+}
+
+/* ================================================== */
+
+int
+CLG_GetClientIndex(IPAddr *client)
+{
+ Record *record;
+
+ record = get_record(client);
+ if (record == NULL)
+ return -1;
+
+ return get_index(record);
+}
+
+/* ================================================== */
+
+int
+CLG_LogNTPAccess(IPAddr *client, struct timespec *now)
+{
+ Record *record;
+
+ total_ntp_hits++;
+
+ record = get_record(client);
+ if (record == NULL)
+ return -1;
+
+ /* Update one of the two rates depending on whether the previous request
+ of the client had a reply or it timed out */
+ update_record(now, &record->last_ntp_hit, &record->ntp_hits,
+ &record->ntp_tokens, max_ntp_tokens, ntp_token_shift,
+ record->flags & FLAG_NTP_DROPPED ?
+ &record->ntp_timeout_rate : &record->ntp_rate);
+
+ DEBUG_LOG("NTP hits %"PRIu32" rate %d trate %d tokens %d",
+ record->ntp_hits, record->ntp_rate, record->ntp_timeout_rate,
+ record->ntp_tokens);
+
+ return get_index(record);
+}
+
+/* ================================================== */
+
+int
+CLG_LogCommandAccess(IPAddr *client, struct timespec *now)
+{
+ Record *record;
+
+ total_cmd_hits++;
+
+ record = get_record(client);
+ if (record == NULL)
+ return -1;
+
+ update_record(now, &record->last_cmd_hit, &record->cmd_hits,
+ &record->cmd_tokens, max_cmd_tokens, cmd_token_shift,
+ &record->cmd_rate);
+
+ DEBUG_LOG("Cmd hits %"PRIu32" rate %d tokens %d",
+ record->cmd_hits, record->cmd_rate, record->cmd_tokens);
+
+ return get_index(record);
+}
+
+/* ================================================== */
+
+static int
+limit_response_random(int leak_rate)
+{
+ static uint32_t rnd;
+ static int bits_left = 0;
+ int r;
+
+ if (bits_left < leak_rate) {
+ UTI_GetRandomBytes(&rnd, sizeof (rnd));
+ bits_left = 8 * sizeof (rnd);
+ }
+
+ /* Return zero on average once per 2^leak_rate */
+ r = rnd % (1U << leak_rate) ? 1 : 0;
+ rnd >>= leak_rate;
+ bits_left -= leak_rate;
+
+ return r;
+}
+
+/* ================================================== */
+
+int
+CLG_LimitNTPResponseRate(int index)
+{
+ Record *record;
+ int drop;
+
+ if (!ntp_tokens_per_packet)
+ return 0;
+
+ record = ARR_GetElement(records, index);
+ record->flags &= ~FLAG_NTP_DROPPED;
+
+ if (record->ntp_tokens >= ntp_tokens_per_packet) {
+ record->ntp_tokens -= ntp_tokens_per_packet;
+ return 0;
+ }
+
+ drop = limit_response_random(ntp_leak_rate);
+
+ /* Poorly implemented clients may send new requests at even a higher rate
+ when they are not getting replies. If the request rate seems to be more
+ than twice as much as when replies are sent, give up on rate limiting to
+ reduce the amount of traffic. Invert the sense of the leak to respond to
+ most of the requests, but still keep the estimated rate updated. */
+ if (record->ntp_timeout_rate != INVALID_RATE &&
+ record->ntp_timeout_rate > record->ntp_rate + RATE_SCALE)
+ drop = !drop;
+
+ if (!drop) {
+ record->ntp_tokens = 0;
+ return 0;
+ }
+
+ record->flags |= FLAG_NTP_DROPPED;
+ record->ntp_drops++;
+ total_ntp_drops++;
+
+ return 1;
+}
+
+/* ================================================== */
+
+int
+CLG_LimitCommandResponseRate(int index)
+{
+ Record *record;
+
+ if (!cmd_tokens_per_packet)
+ return 0;
+
+ record = ARR_GetElement(records, index);
+
+ if (record->cmd_tokens >= cmd_tokens_per_packet) {
+ record->cmd_tokens -= cmd_tokens_per_packet;
+ return 0;
+ }
+
+ if (!limit_response_random(cmd_leak_rate)) {
+ record->cmd_tokens = 0;
+ return 0;
+ }
+
+ record->cmd_drops++;
+ total_cmd_drops++;
+
+ return 1;
+}
+
+/* ================================================== */
+
+void CLG_GetNtpTimestamps(int index, NTP_int64 **rx_ts, NTP_int64 **tx_ts)
+{
+ Record *record;
+
+ record = ARR_GetElement(records, index);
+
+ *rx_ts = &record->ntp_rx_ts;
+ *tx_ts = &record->ntp_tx_ts;
+}
+
+/* ================================================== */
+
+int
+CLG_GetNtpMinPoll(void)
+{
+ return ntp_limit_interval;
+}
+
+/* ================================================== */
+
+int
+CLG_GetNumberOfIndices(void)
+{
+ if (!active)
+ return -1;
+
+ return ARR_GetSize(records);
+}
+
+/* ================================================== */
+
+static int get_interval(int rate)
+{
+ if (rate == INVALID_RATE)
+ return 127;
+
+ rate += rate > 0 ? RATE_SCALE / 2 : -RATE_SCALE / 2;
+
+ return rate / -RATE_SCALE;
+}
+
+/* ================================================== */
+
+static uint32_t get_last_ago(uint32_t x, uint32_t y)
+{
+ if (y == INVALID_TS || (int32_t)(x - y) < 0)
+ return -1;
+
+ return (x - y) >> TS_FRAC;
+}
+
+/* ================================================== */
+
+int
+CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, struct timespec *now)
+{
+ Record *record;
+ uint32_t now_ts;
+
+ if (!active || index < 0 || index >= ARR_GetSize(records))
+ return 0;
+
+ record = ARR_GetElement(records, index);
+
+ if (record->ip_addr.family == IPADDR_UNSPEC)
+ return 0;
+
+ now_ts = get_ts_from_timespec(now);
+
+ report->ip_addr = record->ip_addr;
+ report->ntp_hits = record->ntp_hits;
+ report->cmd_hits = record->cmd_hits;
+ report->ntp_drops = record->ntp_drops;
+ report->cmd_drops = record->cmd_drops;
+ report->ntp_interval = get_interval(record->ntp_rate);
+ report->cmd_interval = get_interval(record->cmd_rate);
+ report->ntp_timeout_interval = get_interval(record->ntp_timeout_rate);
+ report->last_ntp_hit_ago = get_last_ago(now_ts, record->last_ntp_hit);
+ report->last_cmd_hit_ago = get_last_ago(now_ts, record->last_cmd_hit);
+
+ return 1;
+}
+
+/* ================================================== */
+
+void
+CLG_GetServerStatsReport(RPT_ServerStatsReport *report)
+{
+ report->ntp_hits = total_ntp_hits;
+ report->cmd_hits = total_cmd_hits;
+ report->ntp_drops = total_ntp_drops;
+ report->cmd_drops = total_cmd_drops;
+ report->log_drops = total_record_drops;
+}
diff --git a/clientlog.h b/clientlog.h
new file mode 100644
index 0000000..552c767
--- /dev/null
+++ b/clientlog.h
@@ -0,0 +1,50 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow 1997-2003
+ *
+ * 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 contains facilities for logging access by clients.
+
+ */
+
+#ifndef GOT_CLIENTLOG_H
+#define GOT_CLIENTLOG_H
+
+#include "sysincl.h"
+#include "reports.h"
+
+extern void CLG_Initialise(void);
+extern void CLG_Finalise(void);
+extern int CLG_GetClientIndex(IPAddr *client);
+extern int CLG_LogNTPAccess(IPAddr *client, struct timespec *now);
+extern int CLG_LogCommandAccess(IPAddr *client, struct timespec *now);
+extern int CLG_LimitNTPResponseRate(int index);
+extern int CLG_LimitCommandResponseRate(int index);
+extern void CLG_GetNtpTimestamps(int index, NTP_int64 **rx_ts, NTP_int64 **tx_ts);
+extern int CLG_GetNtpMinPoll(void);
+
+/* And some reporting functions, for use by chronyc. */
+
+extern int CLG_GetNumberOfIndices(void);
+extern int CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, struct timespec *now);
+extern void CLG_GetServerStatsReport(RPT_ServerStatsReport *report);
+
+#endif /* GOT_CLIENTLOG_H */
diff --git a/cmdmon.c b/cmdmon.c
new file mode 100644
index 0000000..3b4277a
--- /dev/null
+++ b/cmdmon.c
@@ -0,0 +1,1724 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow 1997-2003
+ * Copyright (C) Miroslav Lichvar 2009-2016, 2018
+ *
+ * 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.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Command and monitoring module in the main program
+ */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "cmdmon.h"
+#include "candm.h"
+#include "sched.h"
+#include "util.h"
+#include "logging.h"
+#include "keys.h"
+#include "ntp_sources.h"
+#include "ntp_core.h"
+#include "smooth.h"
+#include "sources.h"
+#include "sourcestats.h"
+#include "reference.h"
+#include "manual.h"
+#include "memory.h"
+#include "local.h"
+#include "addrfilt.h"
+#include "conf.h"
+#include "rtc.h"
+#include "pktlength.h"
+#include "clientlog.h"
+#include "refclock.h"
+
+/* ================================================== */
+
+union sockaddr_all {
+ struct sockaddr_in in4;
+#ifdef FEAT_IPV6
+ struct sockaddr_in6 in6;
+#endif
+ struct sockaddr_un un;
+ struct sockaddr sa;
+};
+
+/* File descriptors for command and monitoring sockets */
+static int sock_fdu;
+static int sock_fd4;
+#ifdef FEAT_IPV6
+static int sock_fd6;
+#endif
+
+/* Flag indicating whether this module has been initialised or not */
+static int initialised = 0;
+
+/* ================================================== */
+/* Array of permission levels for command types */
+
+static const char permissions[] = {
+ PERMIT_OPEN, /* NULL */
+ PERMIT_AUTH, /* ONLINE */
+ PERMIT_AUTH, /* OFFLINE */
+ PERMIT_AUTH, /* BURST */
+ PERMIT_AUTH, /* MODIFY_MINPOLL */
+ PERMIT_AUTH, /* MODIFY_MAXPOLL */
+ PERMIT_AUTH, /* DUMP */
+ PERMIT_AUTH, /* MODIFY_MAXDELAY */
+ PERMIT_AUTH, /* MODIFY_MAXDELAYRATIO */
+ PERMIT_AUTH, /* MODIFY_MAXUPDATESKEW */
+ PERMIT_OPEN, /* LOGON */
+ PERMIT_AUTH, /* SETTIME */
+ PERMIT_AUTH, /* LOCAL */
+ PERMIT_AUTH, /* MANUAL */
+ PERMIT_OPEN, /* N_SOURCES */
+ PERMIT_OPEN, /* SOURCE_DATA */
+ PERMIT_AUTH, /* REKEY */
+ PERMIT_AUTH, /* ALLOW */
+ PERMIT_AUTH, /* ALLOWALL */
+ PERMIT_AUTH, /* DENY */
+ PERMIT_AUTH, /* DENYALL */
+ PERMIT_AUTH, /* CMDALLOW */
+ PERMIT_AUTH, /* CMDALLOWALL */
+ PERMIT_AUTH, /* CMDDENY */
+ PERMIT_AUTH, /* CMDDENYALL */
+ PERMIT_AUTH, /* ACCHECK */
+ PERMIT_AUTH, /* CMDACCHECK */
+ PERMIT_AUTH, /* ADD_SERVER */
+ PERMIT_AUTH, /* ADD_PEER */
+ PERMIT_AUTH, /* DEL_SOURCE */
+ PERMIT_AUTH, /* WRITERTC */
+ PERMIT_AUTH, /* DFREQ */
+ PERMIT_AUTH, /* DOFFSET */
+ PERMIT_OPEN, /* TRACKING */
+ PERMIT_OPEN, /* SOURCESTATS */
+ PERMIT_OPEN, /* RTCREPORT */
+ PERMIT_AUTH, /* TRIMRTC */
+ PERMIT_AUTH, /* CYCLELOGS */
+ PERMIT_AUTH, /* SUBNETS_ACCESSED */
+ PERMIT_AUTH, /* CLIENT_ACCESSES (by subnet) */
+ PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX */
+ PERMIT_OPEN, /* MANUAL_LIST */
+ PERMIT_AUTH, /* MANUAL_DELETE */
+ PERMIT_AUTH, /* MAKESTEP */
+ PERMIT_OPEN, /* ACTIVITY */
+ PERMIT_AUTH, /* MODIFY_MINSTRATUM */
+ PERMIT_AUTH, /* MODIFY_POLLTARGET */
+ PERMIT_AUTH, /* MODIFY_MAXDELAYDEVRATIO */
+ PERMIT_AUTH, /* RESELECT */
+ PERMIT_AUTH, /* RESELECTDISTANCE */
+ PERMIT_AUTH, /* MODIFY_MAKESTEP */
+ PERMIT_OPEN, /* SMOOTHING */
+ PERMIT_AUTH, /* SMOOTHTIME */
+ PERMIT_AUTH, /* REFRESH */
+ PERMIT_AUTH, /* SERVER_STATS */
+ PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX2 */
+ PERMIT_AUTH, /* LOCAL2 */
+ PERMIT_AUTH, /* NTP_DATA */
+ PERMIT_AUTH, /* ADD_SERVER2 */
+ PERMIT_AUTH, /* ADD_PEER2 */
+ PERMIT_AUTH, /* ADD_SERVER3 */
+ PERMIT_AUTH, /* ADD_PEER3 */
+ PERMIT_AUTH, /* SHUTDOWN */
+ PERMIT_AUTH, /* ONOFFLINE */
+};
+
+/* ================================================== */
+
+/* This authorisation table is used for checking whether particular
+ machines are allowed to make command and monitoring requests. */
+static ADF_AuthTable access_auth_table;
+
+/* ================================================== */
+/* Forward prototypes */
+static void read_from_cmd_socket(int sock_fd, int event, void *anything);
+
+/* ================================================== */
+
+static int
+prepare_socket(int family, int port_number)
+{
+ int sock_fd;
+ socklen_t my_addr_len;
+ union sockaddr_all my_addr;
+ IPAddr bind_address;
+ int on_off = 1;
+
+ sock_fd = socket(family, SOCK_DGRAM, 0);
+ if (sock_fd < 0) {
+ LOG(LOGS_ERR, "Could not open %s command socket : %s",
+ UTI_SockaddrFamilyToString(family), strerror(errno));
+ return -1;
+ }
+
+ /* Close on exec */
+ UTI_FdSetCloexec(sock_fd);
+
+ if (family != AF_UNIX) {
+ /* Allow reuse of port number */
+ if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on_off, sizeof(on_off)) < 0) {
+ LOG(LOGS_ERR, "Could not set reuseaddr socket options");
+ /* Don't quit - we might survive anyway */
+ }
+
+#ifdef IP_FREEBIND
+ /* Allow binding to address that doesn't exist yet */
+ if (setsockopt(sock_fd, IPPROTO_IP, IP_FREEBIND, (char *)&on_off, sizeof(on_off)) < 0) {
+ LOG(LOGS_ERR, "Could not set free bind socket option");
+ }
+#endif
+
+#ifdef FEAT_IPV6
+ if (family == AF_INET6) {
+#ifdef IPV6_V6ONLY
+ /* Receive IPv6 packets only */
+ if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on_off, sizeof(on_off)) < 0) {
+ LOG(LOGS_ERR, "Could not request IPV6_V6ONLY socket option");
+ }
+#endif
+ }
+#endif
+ }
+
+ memset(&my_addr, 0, sizeof (my_addr));
+
+ switch (family) {
+ case AF_INET:
+ my_addr_len = sizeof (my_addr.in4);
+ my_addr.in4.sin_family = family;
+ my_addr.in4.sin_port = htons((unsigned short)port_number);
+
+ CNF_GetBindCommandAddress(IPADDR_INET4, &bind_address);
+
+ 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_LOOPBACK);
+ break;
+#ifdef FEAT_IPV6
+ case AF_INET6:
+ my_addr_len = sizeof (my_addr.in6);
+ my_addr.in6.sin6_family = family;
+ my_addr.in6.sin6_port = htons((unsigned short)port_number);
+
+ CNF_GetBindCommandAddress(IPADDR_INET6, &bind_address);
+
+ if (bind_address.family == IPADDR_INET6)
+ 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_loopback;
+ break;
+#endif
+ case AF_UNIX:
+ my_addr_len = sizeof (my_addr.un);
+ my_addr.un.sun_family = family;
+ if (snprintf(my_addr.un.sun_path, sizeof (my_addr.un.sun_path), "%s",
+ CNF_GetBindCommandPath()) >= sizeof (my_addr.un.sun_path))
+ LOG_FATAL("Unix socket path too long");
+ unlink(my_addr.un.sun_path);
+ break;
+ default:
+ assert(0);
+ }
+
+ if (bind(sock_fd, &my_addr.sa, my_addr_len) < 0) {
+ LOG(LOGS_ERR, "Could not bind %s command socket : %s",
+ UTI_SockaddrFamilyToString(family), strerror(errno));
+ close(sock_fd);
+ return -1;
+ }
+
+ /* Register handler for read events on the socket */
+ SCH_AddFileHandler(sock_fd, SCH_FILE_INPUT, read_from_cmd_socket, NULL);
+
+ return sock_fd;
+}
+
+/* ================================================== */
+
+static void
+do_size_checks(void)
+{
+ int i, request_length, padding_length, reply_length;
+ CMD_Request request;
+ CMD_Reply reply;
+
+ assert(offsetof(CMD_Request, data) == 20);
+ assert(offsetof(CMD_Reply, data) == 28);
+
+ for (i = 0; i < N_REQUEST_TYPES; i++) {
+ request.version = PROTO_VERSION_NUMBER;
+ request.command = htons(i);
+ request_length = PKL_CommandLength(&request);
+ padding_length = PKL_CommandPaddingLength(&request);
+ if (padding_length > MAX_PADDING_LENGTH || padding_length > request_length ||
+ request_length > sizeof (CMD_Request) ||
+ (request_length && request_length < offsetof(CMD_Request, data)))
+ assert(0);
+ }
+
+ for (i = 1; i < N_REPLY_TYPES; i++) {
+ reply.reply = htons(i);
+ reply.status = STT_SUCCESS;
+ reply_length = PKL_ReplyLength(&reply);
+ if ((reply_length && reply_length < offsetof(CMD_Reply, data)) ||
+ reply_length > sizeof (CMD_Reply))
+ assert(0);
+ }
+}
+
+/* ================================================== */
+
+void
+CAM_Initialise(int family)
+{
+ int port_number;
+
+ assert(!initialised);
+ assert(sizeof (permissions) / sizeof (permissions[0]) == N_REQUEST_TYPES);
+ do_size_checks();
+
+ initialised = 1;
+ sock_fdu = -1;
+ port_number = CNF_GetCommandPort();
+
+ if (port_number && (family == IPADDR_UNSPEC || family == IPADDR_INET4))
+ sock_fd4 = prepare_socket(AF_INET, port_number);
+ else
+ sock_fd4 = -1;
+#ifdef FEAT_IPV6
+ if (port_number && (family == IPADDR_UNSPEC || family == IPADDR_INET6))
+ sock_fd6 = prepare_socket(AF_INET6, port_number);
+ else
+ sock_fd6 = -1;
+#endif
+
+ if (port_number && sock_fd4 < 0
+#ifdef FEAT_IPV6
+ && sock_fd6 < 0
+#endif
+ ) {
+ LOG_FATAL("Could not open any command socket");
+ }
+
+ access_auth_table = ADF_CreateTable();
+
+}
+
+/* ================================================== */
+
+void
+CAM_Finalise(void)
+{
+ if (sock_fdu >= 0) {
+ SCH_RemoveFileHandler(sock_fdu);
+ close(sock_fdu);
+ unlink(CNF_GetBindCommandPath());
+ }
+ sock_fdu = -1;
+ if (sock_fd4 >= 0) {
+ SCH_RemoveFileHandler(sock_fd4);
+ close(sock_fd4);
+ }
+ sock_fd4 = -1;
+#ifdef FEAT_IPV6
+ if (sock_fd6 >= 0) {
+ SCH_RemoveFileHandler(sock_fd6);
+ close(sock_fd6);
+ }
+ sock_fd6 = -1;
+#endif
+
+ ADF_DestroyTable(access_auth_table);
+
+ initialised = 0;
+}
+
+/* ================================================== */
+
+void
+CAM_OpenUnixSocket(void)
+{
+ /* This is separated from CAM_Initialise() as it needs to be called when
+ the process has already dropped the root privileges */
+ if (CNF_GetBindCommandPath()[0])
+ sock_fdu = prepare_socket(AF_UNIX, 0);
+}
+
+/* ================================================== */
+
+static void
+transmit_reply(CMD_Reply *msg, union sockaddr_all *where_to)
+{
+ int status;
+ int tx_message_length;
+ int sock_fd;
+ socklen_t addrlen;
+
+ switch (where_to->sa.sa_family) {
+ case AF_INET:
+ sock_fd = sock_fd4;
+ addrlen = sizeof (where_to->in4);
+ break;
+#ifdef FEAT_IPV6
+ case AF_INET6:
+ sock_fd = sock_fd6;
+ addrlen = sizeof (where_to->in6);
+ break;
+#endif
+ case AF_UNIX:
+ sock_fd = sock_fdu;
+ addrlen = sizeof (where_to->un);
+ break;
+ default:
+ assert(0);
+ }
+
+ tx_message_length = PKL_ReplyLength(msg);
+ status = sendto(sock_fd, (void *) msg, tx_message_length, 0,
+ &where_to->sa, addrlen);
+
+ if (status < 0) {
+ DEBUG_LOG("Could not send to %s fd %d : %s",
+ UTI_SockaddrToString(&where_to->sa), sock_fd, strerror(errno));
+ return;
+ }
+
+ DEBUG_LOG("Sent %d bytes to %s fd %d", status,
+ UTI_SockaddrToString(&where_to->sa), sock_fd);
+}
+
+/* ================================================== */
+
+static void
+handle_dump(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ SRC_DumpSources();
+}
+
+/* ================================================== */
+
+static void
+handle_online(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr address, mask;
+
+ UTI_IPNetworkToHost(&rx_message->data.online.mask, &mask);
+ UTI_IPNetworkToHost(&rx_message->data.online.address, &address);
+ if (!NSR_SetConnectivity(&mask, &address, SRC_ONLINE))
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+}
+
+/* ================================================== */
+
+static void
+handle_offline(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr address, mask;
+
+ UTI_IPNetworkToHost(&rx_message->data.offline.mask, &mask);
+ UTI_IPNetworkToHost(&rx_message->data.offline.address, &address);
+ if (!NSR_SetConnectivity(&mask, &address, SRC_OFFLINE))
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+}
+
+/* ================================================== */
+
+static void
+handle_onoffline(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr address, mask;
+
+ address.family = mask.family = IPADDR_UNSPEC;
+ if (!NSR_SetConnectivity(&mask, &address, SRC_MAYBE_ONLINE))
+ ;
+}
+
+/* ================================================== */
+
+static void
+handle_burst(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr address, mask;
+
+ UTI_IPNetworkToHost(&rx_message->data.burst.mask, &mask);
+ UTI_IPNetworkToHost(&rx_message->data.burst.address, &address);
+ 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);
+}
+
+/* ================================================== */
+
+static void
+handle_modify_minpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr address;
+
+ UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
+ if (!NSR_ModifyMinpoll(&address,
+ ntohl(rx_message->data.modify_minpoll.new_minpoll)))
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+}
+
+/* ================================================== */
+
+static void
+handle_modify_maxpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr address;
+
+ UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
+ if (!NSR_ModifyMaxpoll(&address,
+ ntohl(rx_message->data.modify_minpoll.new_minpoll)))
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+}
+
+/* ================================================== */
+
+static void
+handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr address;
+
+ UTI_IPNetworkToHost(&rx_message->data.modify_maxdelay.address, &address);
+ if (!NSR_ModifyMaxdelay(&address,
+ UTI_FloatNetworkToHost(rx_message->data.modify_maxdelay.new_max_delay)))
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+}
+
+/* ================================================== */
+
+static void
+handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr address;
+
+ UTI_IPNetworkToHost(&rx_message->data.modify_maxdelayratio.address, &address);
+ if (!NSR_ModifyMaxdelayratio(&address,
+ UTI_FloatNetworkToHost(rx_message->data.modify_maxdelayratio.new_max_delay_ratio)))
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+}
+
+/* ================================================== */
+
+static void
+handle_modify_maxdelaydevratio(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr address;
+
+ UTI_IPNetworkToHost(&rx_message->data.modify_maxdelaydevratio.address, &address);
+ if (!NSR_ModifyMaxdelaydevratio(&address,
+ UTI_FloatNetworkToHost(rx_message->data.modify_maxdelaydevratio.new_max_delay_dev_ratio)))
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+}
+
+/* ================================================== */
+
+static void
+handle_modify_minstratum(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr address;
+
+ UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
+ if (!NSR_ModifyMinstratum(&address,
+ ntohl(rx_message->data.modify_minstratum.new_min_stratum)))
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+}
+
+/* ================================================== */
+
+static void
+handle_modify_polltarget(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr address;
+
+ UTI_IPNetworkToHost(&rx_message->data.modify_polltarget.address, &address);
+ if (!NSR_ModifyPolltarget(&address,
+ ntohl(rx_message->data.modify_polltarget.new_poll_target)))
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+}
+
+/* ================================================== */
+
+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));
+}
+
+/* ================================================== */
+
+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));
+}
+
+/* ================================================== */
+
+static void
+handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ struct timespec ts;
+ double offset, dfreq_ppm, new_afreq_ppm;
+ UTI_TimespecNetworkToHost(&rx_message->data.settime.ts, &ts);
+ if (!MNL_IsEnabled()) {
+ tx_message->status = htons(STT_NOTENABLED);
+ } else if (MNL_AcceptTimestamp(&ts, &offset, &dfreq_ppm, &new_afreq_ppm)) {
+ tx_message->reply = htons(RPY_MANUAL_TIMESTAMP2);
+ tx_message->data.manual_timestamp.offset = UTI_FloatHostToNetwork(offset);
+ 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_FAILED);
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_local(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ if (ntohl(rx_message->data.local.on_off)) {
+ REF_EnableLocal(ntohl(rx_message->data.local.stratum),
+ UTI_FloatNetworkToHost(rx_message->data.local.distance),
+ ntohl(rx_message->data.local.orphan));
+ } else {
+ REF_DisableLocal();
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_manual(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ int option;
+ option = ntohl(rx_message->data.manual.option);
+ switch (option) {
+ case 0:
+ MNL_Disable();
+ break;
+ case 1:
+ MNL_Enable();
+ break;
+ case 2:
+ MNL_Reset();
+ break;
+ default:
+ tx_message->status = htons(STT_INVALID);
+ break;
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_n_sources(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ int n_sources;
+ n_sources = SRC_ReadNumberOfSources();
+ tx_message->reply = htons(RPY_N_SOURCES);
+ tx_message->data.n_sources.n_sources = htonl(n_sources);
+}
+
+/* ================================================== */
+
+static void
+handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ RPT_SourceReport report;
+ struct timespec now_corr;
+
+ /* Get data */
+ 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:
+ NSR_ReportSource(&report, &now_corr);
+ break;
+ case SRC_REFCLOCK:
+ RCL_ReportSource(&report, &now_corr);
+ break;
+ }
+
+ tx_message->reply = htons(RPY_SOURCE_DATA);
+
+ UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.source_data.ip_addr);
+ tx_message->data.source_data.stratum = htons(report.stratum);
+ tx_message->data.source_data.poll = htons(report.poll);
+ switch (report.state) {
+ case RPT_SYNC:
+ tx_message->data.source_data.state = htons(RPY_SD_ST_SYNC);
+ break;
+ case RPT_UNREACH:
+ tx_message->data.source_data.state = htons(RPY_SD_ST_UNREACH);
+ break;
+ case RPT_FALSETICKER:
+ tx_message->data.source_data.state = htons(RPY_SD_ST_FALSETICKER);
+ break;
+ case RPT_JITTERY:
+ tx_message->data.source_data.state = htons(RPY_SD_ST_JITTERY);
+ break;
+ case RPT_CANDIDATE:
+ tx_message->data.source_data.state = htons(RPY_SD_ST_CANDIDATE);
+ break;
+ case RPT_OUTLIER:
+ tx_message->data.source_data.state = htons(RPY_SD_ST_OUTLIER);
+ break;
+ }
+ switch (report.mode) {
+ case RPT_NTP_CLIENT:
+ tx_message->data.source_data.mode = htons(RPY_SD_MD_CLIENT);
+ break;
+ case RPT_NTP_PEER:
+ tx_message->data.source_data.mode = htons(RPY_SD_MD_PEER);
+ break;
+ case RPT_LOCAL_REFERENCE:
+ tx_message->data.source_data.mode = htons(RPY_SD_MD_REF);
+ break;
+ }
+ tx_message->data.source_data.flags =
+ htons((report.sel_options & SRC_SELECT_PREFER ? RPY_SD_FLAG_PREFER : 0) |
+ (report.sel_options & SRC_SELECT_NOSELECT ? RPY_SD_FLAG_NOSELECT : 0) |
+ (report.sel_options & SRC_SELECT_TRUST ? RPY_SD_FLAG_TRUST : 0) |
+ (report.sel_options & SRC_SELECT_REQUIRE ? RPY_SD_FLAG_REQUIRE : 0));
+ tx_message->data.source_data.reachability = htons(report.reachability);
+ tx_message->data.source_data.since_sample = htonl(report.latest_meas_ago);
+ tx_message->data.source_data.orig_latest_meas = UTI_FloatHostToNetwork(report.orig_latest_meas);
+ tx_message->data.source_data.latest_meas = UTI_FloatHostToNetwork(report.latest_meas);
+ tx_message->data.source_data.latest_meas_err = UTI_FloatHostToNetwork(report.latest_meas_err);
+ } else {
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_rekey(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ KEY_Reload();
+}
+
+/* ================================================== */
+
+static void
+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, allow, all))
+ tx_message->status = htons(STT_BADSUBNET);
+}
+
+/* ================================================== */
+
+static void
+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, allow, all))
+ tx_message->status = htons(STT_BADSUBNET);
+}
+
+/* ================================================== */
+
+static void
+handle_accheck(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr ip;
+ UTI_IPNetworkToHost(&rx_message->data.ac_check.ip, &ip);
+ if (NCR_CheckAccessRestriction(&ip)) {
+ tx_message->status = htons(STT_ACCESSALLOWED);
+ } else {
+ tx_message->status = htons(STT_ACCESSDENIED);
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_cmdaccheck(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ IPAddr ip;
+ UTI_IPNetworkToHost(&rx_message->data.ac_check.ip, &ip);
+ if (CAM_CheckAccessRestriction(&ip)) {
+ tx_message->status = htons(STT_ACCESSALLOWED);
+ } else {
+ tx_message->status = htons(STT_ACCESSDENIED);
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ NTP_Remote_Address rem_addr;
+ SourceParameters params;
+ NSR_Status status;
+
+ UTI_IPNetworkToHost(&rx_message->data.ntp_source.ip_addr, &rem_addr.ip_addr);
+ rem_addr.port = (unsigned short)(ntohl(rx_message->data.ntp_source.port));
+ params.minpoll = ntohl(rx_message->data.ntp_source.minpoll);
+ params.maxpoll = ntohl(rx_message->data.ntp_source.maxpoll);
+ params.presend_minpoll = ntohl(rx_message->data.ntp_source.presend_minpoll);
+ params.min_stratum = ntohl(rx_message->data.ntp_source.min_stratum);
+ params.poll_target = ntohl(rx_message->data.ntp_source.poll_target);
+ params.version = ntohl(rx_message->data.ntp_source.version);
+ params.max_sources = ntohl(rx_message->data.ntp_source.max_sources);
+ params.min_samples = ntohl(rx_message->data.ntp_source.min_samples);
+ params.max_samples = ntohl(rx_message->data.ntp_source.max_samples);
+ params.filter_length = ntohl(rx_message->data.ntp_source.filter_length);
+ params.authkey = ntohl(rx_message->data.ntp_source.authkey);
+ params.max_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay);
+ params.max_delay_ratio =
+ UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio);
+ params.max_delay_dev_ratio =
+ UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_dev_ratio);
+ params.min_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.min_delay);
+ params.asymmetry = UTI_FloatNetworkToHost(rx_message->data.ntp_source.asymmetry);
+ params.offset = UTI_FloatNetworkToHost(rx_message->data.ntp_source.offset);
+
+ params.connectivity = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ?
+ SRC_ONLINE : SRC_OFFLINE;
+ params.auto_offline = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_AUTOOFFLINE ? 1 : 0;
+ params.iburst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_IBURST ? 1 : 0;
+ params.interleaved = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_INTERLEAVED ? 1 : 0;
+ params.burst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_BURST ? 1 : 0;
+ params.sel_options =
+ (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_PREFER ? SRC_SELECT_PREFER : 0) |
+ (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NOSELECT ? SRC_SELECT_NOSELECT : 0) |
+ (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_TRUST ? SRC_SELECT_TRUST : 0) |
+ (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_REQUIRE ? SRC_SELECT_REQUIRE : 0);
+
+ status = NSR_AddSource(&rem_addr, type, &params);
+ switch (status) {
+ case NSR_Success:
+ break;
+ case NSR_AlreadyInUse:
+ tx_message->status = htons(STT_SOURCEALREADYKNOWN);
+ break;
+ case NSR_TooManySources:
+ tx_message->status = htons(STT_TOOMANYSOURCES);
+ break;
+ case NSR_InvalidAF:
+ tx_message->status = htons(STT_INVALIDAF);
+ break;
+ case NSR_NoSuchSource:
+ assert(0);
+ break;
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_del_source(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ NTP_Remote_Address rem_addr;
+ NSR_Status status;
+
+ UTI_IPNetworkToHost(&rx_message->data.del_source.ip_addr, &rem_addr.ip_addr);
+ rem_addr.port = 0;
+
+ status = NSR_RemoveSource(&rem_addr);
+ switch (status) {
+ case NSR_Success:
+ break;
+ case NSR_NoSuchSource:
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+ break;
+ case NSR_TooManySources:
+ case NSR_AlreadyInUse:
+ case NSR_InvalidAF:
+ assert(0);
+ break;
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_writertc(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ switch (RTC_WriteParameters()) {
+ case RTC_ST_OK:
+ break;
+ case RTC_ST_NODRV:
+ tx_message->status = htons(STT_NORTC);
+ break;
+ case RTC_ST_BADFILE:
+ tx_message->status = htons(STT_BADRTCFILE);
+ break;
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_dfreq(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ double dfreq;
+ dfreq = UTI_FloatNetworkToHost(rx_message->data.dfreq.dfreq);
+ LCL_AccumulateDeltaFrequency(dfreq * 1.0e-6);
+ LOG(LOGS_INFO, "Accumulated delta freq of %.3fppm", dfreq);
+}
+
+/* ================================================== */
+
+static void
+handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ long sec, usec;
+ double doffset;
+ sec = (int32_t)ntohl(rx_message->data.doffset.sec);
+ usec = (int32_t)ntohl(rx_message->data.doffset.usec);
+ doffset = (double) sec + 1.0e-6 * (double) usec;
+ LOG(LOGS_INFO, "Accumulated delta offset of %.6f seconds", doffset);
+ LCL_AccumulateOffset(doffset, 0.0);
+}
+
+/* ================================================== */
+
+static void
+handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ RPT_TrackingReport rpt;
+
+ REF_GetTrackingReport(&rpt);
+ tx_message->reply = htons(RPY_TRACKING);
+ tx_message->data.tracking.ref_id = htonl(rpt.ref_id);
+ UTI_IPHostToNetwork(&rpt.ip_addr, &tx_message->data.tracking.ip_addr);
+ tx_message->data.tracking.stratum = htons(rpt.stratum);
+ tx_message->data.tracking.leap_status = htons(rpt.leap_status);
+ UTI_TimespecHostToNetwork(&rpt.ref_time, &tx_message->data.tracking.ref_time);
+ tx_message->data.tracking.current_correction = UTI_FloatHostToNetwork(rpt.current_correction);
+ tx_message->data.tracking.last_offset = UTI_FloatHostToNetwork(rpt.last_offset);
+ tx_message->data.tracking.rms_offset = UTI_FloatHostToNetwork(rpt.rms_offset);
+ tx_message->data.tracking.freq_ppm = UTI_FloatHostToNetwork(rpt.freq_ppm);
+ tx_message->data.tracking.resid_freq_ppm = UTI_FloatHostToNetwork(rpt.resid_freq_ppm);
+ tx_message->data.tracking.skew_ppm = UTI_FloatHostToNetwork(rpt.skew_ppm);
+ tx_message->data.tracking.root_delay = UTI_FloatHostToNetwork(rpt.root_delay);
+ tx_message->data.tracking.root_dispersion = UTI_FloatHostToNetwork(rpt.root_dispersion);
+ tx_message->data.tracking.last_update_interval = UTI_FloatHostToNetwork(rpt.last_update_interval);
+}
+
+/* ================================================== */
+
+static void
+handle_smoothing(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ RPT_SmoothingReport report;
+ struct timespec 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 timespec 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 timespec now_corr;
+
+ SCH_GetLastEventTime(&now_corr, NULL, NULL);
+ status = SRC_ReportSourcestats(ntohl(rx_message->data.sourcestats.index),
+ &report, &now_corr);
+
+ if (status) {
+ 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);
+ tx_message->data.sourcestats.n_samples = htonl(report.n_samples);
+ tx_message->data.sourcestats.n_runs = htonl(report.n_runs);
+ tx_message->data.sourcestats.span_seconds = htonl(report.span_seconds);
+ tx_message->data.sourcestats.resid_freq_ppm = UTI_FloatHostToNetwork(report.resid_freq_ppm);
+ tx_message->data.sourcestats.skew_ppm = UTI_FloatHostToNetwork(report.skew_ppm);
+ tx_message->data.sourcestats.sd = UTI_FloatHostToNetwork(report.sd);
+ tx_message->data.sourcestats.est_offset = UTI_FloatHostToNetwork(report.est_offset);
+ tx_message->data.sourcestats.est_offset_err = UTI_FloatHostToNetwork(report.est_offset_err);
+ } else {
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ int status;
+ RPT_RTC_Report report;
+ status = RTC_GetReport(&report);
+ if (status) {
+ tx_message->reply = htons(RPY_RTC);
+ UTI_TimespecHostToNetwork(&report.ref_time, &tx_message->data.rtc.ref_time);
+ tx_message->data.rtc.n_samples = htons(report.n_samples);
+ tx_message->data.rtc.n_runs = htons(report.n_runs);
+ tx_message->data.rtc.span_seconds = htonl(report.span_seconds);
+ tx_message->data.rtc.rtc_seconds_fast = UTI_FloatHostToNetwork(report.rtc_seconds_fast);
+ tx_message->data.rtc.rtc_gain_rate_ppm = UTI_FloatHostToNetwork(report.rtc_gain_rate_ppm);
+ } else {
+ tx_message->status = htons(STT_NORTC);
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_trimrtc(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ if (!RTC_Trim())
+ tx_message->status = htons(STT_NORTC);
+}
+
+/* ================================================== */
+
+static void
+handle_cyclelogs(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ LOG_CycleLogFiles();
+}
+
+/* ================================================== */
+
+static void
+handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ RPT_ClientAccessByIndex_Report report;
+ RPY_ClientAccesses_Client *client;
+ int n_indices;
+ uint32_t i, j, req_first_index, req_n_clients;
+ struct timespec now;
+
+ SCH_GetLastEventTime(&now, NULL, NULL);
+
+ req_first_index = ntohl(rx_message->data.client_accesses_by_index.first_index);
+ req_n_clients = ntohl(rx_message->data.client_accesses_by_index.n_clients);
+ if (req_n_clients > MAX_CLIENT_ACCESSES)
+ req_n_clients = MAX_CLIENT_ACCESSES;
+
+ n_indices = CLG_GetNumberOfIndices();
+ if (n_indices < 0) {
+ tx_message->status = htons(STT_INACTIVE);
+ return;
+ }
+
+ tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX2);
+ tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices);
+
+ for (i = req_first_index, j = 0; i < (uint32_t)n_indices && j < req_n_clients; i++) {
+ if (!CLG_GetClientAccessReportByIndex(i, &report, &now))
+ continue;
+
+ client = &tx_message->data.client_accesses_by_index.clients[j++];
+
+ UTI_IPHostToNetwork(&report.ip_addr, &client->ip);
+ client->ntp_hits = htonl(report.ntp_hits);
+ client->cmd_hits = htonl(report.cmd_hits);
+ client->ntp_drops = htonl(report.ntp_drops);
+ client->cmd_drops = htonl(report.cmd_drops);
+ client->ntp_interval = report.ntp_interval;
+ client->cmd_interval = report.cmd_interval;
+ client->ntp_timeout_interval = report.ntp_timeout_interval;
+ client->last_ntp_hit_ago = htonl(report.last_ntp_hit_ago);
+ client->last_cmd_hit_ago = htonl(report.last_cmd_hit_ago);
+ }
+
+ tx_message->data.client_accesses_by_index.next_index = htonl(i);
+ tx_message->data.client_accesses_by_index.n_clients = htonl(j);
+}
+
+/* ================================================== */
+
+static void
+handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ int n_samples;
+ int i;
+ RPY_ManualListSample *sample;
+ RPT_ManualSamplesReport report[MAX_MANUAL_LIST_SAMPLES];
+
+ tx_message->reply = htons(RPY_MANUAL_LIST2);
+
+ MNL_ReportSamples(report, MAX_MANUAL_LIST_SAMPLES, &n_samples);
+ tx_message->data.manual_list.n_samples = htonl(n_samples);
+
+ for (i=0; i<n_samples; i++) {
+ sample = &tx_message->data.manual_list.samples[i];
+ UTI_TimespecHostToNetwork(&report[i].when, &sample->when);
+ sample->slewed_offset = UTI_FloatHostToNetwork(report[i].slewed_offset);
+ sample->orig_offset = UTI_FloatHostToNetwork(report[i].orig_offset);
+ sample->residual = UTI_FloatHostToNetwork(report[i].residual);
+ }
+}
+
+/* ================================================== */
+
+static void
+handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ int index;
+
+ index = ntohl(rx_message->data.manual_delete.index);
+ if (!MNL_DeleteSample(index))
+ tx_message->status = htons(STT_BADSAMPLE);
+}
+
+/* ================================================== */
+
+static void
+handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ if (!LCL_MakeStep())
+ tx_message->status = htons(STT_FAILED);
+}
+
+/* ================================================== */
+
+static void
+handle_activity(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ RPT_ActivityReport report;
+ NSR_GetActivityReport(&report);
+ tx_message->data.activity.online = htonl(report.online);
+ tx_message->data.activity.offline = htonl(report.offline);
+ tx_message->data.activity.burst_online = htonl(report.burst_online);
+ tx_message->data.activity.burst_offline = htonl(report.burst_offline);
+ tx_message->data.activity.unresolved = htonl(report.unresolved);
+ tx_message->reply = htons(RPY_ACTIVITY);
+}
+
+/* ================================================== */
+
+static void
+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);
+}
+
+/* ================================================== */
+
+static void
+handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ SRC_ReselectSource();
+}
+
+/* ================================================== */
+
+static void
+handle_refresh(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ NSR_RefreshAddresses();
+}
+
+/* ================================================== */
+
+static void
+handle_server_stats(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ RPT_ServerStatsReport report;
+
+ CLG_GetServerStatsReport(&report);
+ tx_message->reply = htons(RPY_SERVER_STATS);
+ tx_message->data.server_stats.ntp_hits = htonl(report.ntp_hits);
+ tx_message->data.server_stats.cmd_hits = htonl(report.cmd_hits);
+ tx_message->data.server_stats.ntp_drops = htonl(report.ntp_drops);
+ tx_message->data.server_stats.cmd_drops = htonl(report.cmd_drops);
+ tx_message->data.server_stats.log_drops = htonl(report.log_drops);
+}
+
+/* ================================================== */
+
+static void
+handle_ntp_data(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ RPT_NTPReport report;
+
+ UTI_IPNetworkToHost(&rx_message->data.ntp_data.ip_addr, &report.remote_addr);
+
+ if (!NSR_GetNTPReport(&report)) {
+ tx_message->status = htons(STT_NOSUCHSOURCE);
+ return;
+ }
+
+ tx_message->reply = htons(RPY_NTP_DATA);
+ UTI_IPHostToNetwork(&report.remote_addr, &tx_message->data.ntp_data.remote_addr);
+ UTI_IPHostToNetwork(&report.local_addr, &tx_message->data.ntp_data.local_addr);
+ tx_message->data.ntp_data.remote_port = htons(report.remote_port);
+ tx_message->data.ntp_data.leap = report.leap;
+ tx_message->data.ntp_data.version = report.version;
+ tx_message->data.ntp_data.mode = report.mode;
+ tx_message->data.ntp_data.stratum = report.stratum;
+ tx_message->data.ntp_data.poll = report.poll;
+ tx_message->data.ntp_data.precision = report.precision;
+ tx_message->data.ntp_data.root_delay = UTI_FloatHostToNetwork(report.root_delay);
+ tx_message->data.ntp_data.root_dispersion = UTI_FloatHostToNetwork(report.root_dispersion);
+ tx_message->data.ntp_data.ref_id = htonl(report.ref_id);
+ UTI_TimespecHostToNetwork(&report.ref_time, &tx_message->data.ntp_data.ref_time);
+ tx_message->data.ntp_data.offset = UTI_FloatHostToNetwork(report.offset);
+ tx_message->data.ntp_data.peer_delay = UTI_FloatHostToNetwork(report.peer_delay);
+ tx_message->data.ntp_data.peer_dispersion = UTI_FloatHostToNetwork(report.peer_dispersion);
+ tx_message->data.ntp_data.response_time = UTI_FloatHostToNetwork(report.response_time);
+ tx_message->data.ntp_data.jitter_asymmetry = UTI_FloatHostToNetwork(report.jitter_asymmetry);
+ tx_message->data.ntp_data.flags = htons((report.tests & RPY_NTP_FLAGS_TESTS) |
+ (report.interleaved ? RPY_NTP_FLAG_INTERLEAVED : 0) |
+ (report.authenticated ? RPY_NTP_FLAG_AUTHENTICATED : 0));
+ tx_message->data.ntp_data.tx_tss_char = report.tx_tss_char;
+ tx_message->data.ntp_data.rx_tss_char = report.rx_tss_char;
+ tx_message->data.ntp_data.total_tx_count = htonl(report.total_tx_count);
+ tx_message->data.ntp_data.total_rx_count = htonl(report.total_rx_count);
+ tx_message->data.ntp_data.total_valid_count = htonl(report.total_valid_count);
+ memset(tx_message->data.ntp_data.reserved, 0xff, sizeof (tx_message->data.ntp_data.reserved));
+}
+
+/* ================================================== */
+
+static void
+handle_shutdown(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+ LOG(LOGS_INFO, "Received shutdown command");
+ SCH_QuitProgram();
+}
+
+/* ================================================== */
+/* Read a packet and process it */
+
+static void
+read_from_cmd_socket(int sock_fd, int event, void *anything)
+{
+ CMD_Request rx_message;
+ CMD_Reply tx_message;
+ int status, read_length, expected_length, rx_message_length;
+ int localhost, allowed, log_index;
+ union sockaddr_all where_from;
+ socklen_t from_length;
+ IPAddr remote_ip;
+ unsigned short remote_port, rx_command;
+ struct timespec now, cooked_now;
+
+ rx_message_length = sizeof(rx_message);
+ from_length = sizeof(where_from);
+
+ status = recvfrom(sock_fd, (char *)&rx_message, rx_message_length, 0,
+ &where_from.sa, &from_length);
+
+ if (status < 0) {
+ LOG(LOGS_WARN, "Error [%s] reading from control socket %d",
+ strerror(errno), sock_fd);
+ return;
+ }
+
+ if (from_length > sizeof (where_from) ||
+ from_length <= sizeof (where_from.sa.sa_family)) {
+ DEBUG_LOG("Read command packet without source address");
+ return;
+ }
+
+ read_length = status;
+
+ /* Get current time cheaply */
+ SCH_GetLastEventTime(&cooked_now, NULL, &now);
+
+ UTI_SockaddrToIPAndPort(&where_from.sa, &remote_ip, &remote_port);
+
+ /* Check if it's from localhost (127.0.0.1, ::1, or Unix domain) */
+ switch (remote_ip.family) {
+ case IPADDR_INET4:
+ assert(sock_fd == sock_fd4);
+ localhost = remote_ip.addr.in4 == INADDR_LOOPBACK;
+ break;
+#ifdef FEAT_IPV6
+ case IPADDR_INET6:
+ assert(sock_fd == sock_fd6);
+ localhost = !memcmp(remote_ip.addr.in6, &in6addr_loopback,
+ sizeof (in6addr_loopback));
+ break;
+#endif
+ case IPADDR_UNSPEC:
+ /* This should be the Unix domain socket */
+ if (where_from.sa.sa_family != AF_UNIX)
+ return;
+ assert(sock_fd == sock_fdu);
+ localhost = 1;
+ break;
+ default:
+ assert(0);
+ }
+
+ DEBUG_LOG("Received %d bytes from %s fd %d",
+ status, UTI_SockaddrToString(&where_from.sa), sock_fd);
+
+ if (!(localhost || ADF_IsAllowed(access_auth_table, &remote_ip))) {
+ /* The client is not allowed access, so don't waste any more time
+ on him. Note that localhost is always allowed access
+ regardless of the defined access rules - otherwise, we could
+ shut ourselves out completely! */
+ return;
+ }
+
+ if (read_length < offsetof(CMD_Request, data) ||
+ read_length < offsetof(CMD_Reply, data) ||
+ rx_message.pkt_type != PKT_TYPE_CMD_REQUEST ||
+ rx_message.res1 != 0 ||
+ rx_message.res2 != 0) {
+
+ /* We don't know how to process anything like this or an error reply
+ would be larger than the request */
+ DEBUG_LOG("Command packet dropped");
+ return;
+ }
+
+ expected_length = PKL_CommandLength(&rx_message);
+ rx_command = ntohs(rx_message.command);
+
+ memset(&tx_message, 0, sizeof (tx_message));
+
+ tx_message.version = PROTO_VERSION_NUMBER;
+ tx_message.pkt_type = PKT_TYPE_CMD_REPLY;
+ tx_message.command = rx_message.command;
+ tx_message.reply = htons(RPY_NULL);
+ tx_message.status = htons(STT_SUCCESS);
+ tx_message.sequence = rx_message.sequence;
+
+ if (rx_message.version != PROTO_VERSION_NUMBER) {
+ DEBUG_LOG("Command packet has invalid version (%d != %d)",
+ rx_message.version, PROTO_VERSION_NUMBER);
+
+ if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT_SERVER) {
+ tx_message.status = htons(STT_BADPKTVERSION);
+ transmit_reply(&tx_message, &where_from);
+ }
+ return;
+ }
+
+ if (rx_command >= N_REQUEST_TYPES ||
+ expected_length < (int)offsetof(CMD_Request, data)) {
+ DEBUG_LOG("Command packet has invalid command %d", rx_command);
+
+ tx_message.status = htons(STT_INVALID);
+ transmit_reply(&tx_message, &where_from);
+ return;
+ }
+
+ if (read_length < expected_length) {
+ DEBUG_LOG("Command packet is too short (%d < %d)", read_length,
+ expected_length);
+
+ tx_message.status = htons(STT_BADPKTLENGTH);
+ transmit_reply(&tx_message, &where_from);
+ return;
+ }
+
+ /* OK, we have a valid message. Now dispatch on message type and process it. */
+
+ log_index = CLG_LogCommandAccess(&remote_ip, &cooked_now);
+
+ /* Don't reply to all requests from hosts other than localhost if the rate
+ is excessive */
+ if (!localhost && log_index >= 0 && CLG_LimitCommandResponseRate(log_index)) {
+ DEBUG_LOG("Command packet discarded to limit response rate");
+ return;
+ }
+
+ if (rx_command >= N_REQUEST_TYPES) {
+ /* This should be already handled */
+ assert(0);
+ } else {
+ /* Check level of authority required to issue the command. All commands
+ from the Unix domain socket (which is accessible only by the root and
+ chrony user/group) are allowed. */
+ if (where_from.sa.sa_family == AF_UNIX) {
+ assert(sock_fd == sock_fdu);
+ allowed = 1;
+ } else {
+ switch (permissions[rx_command]) {
+ case PERMIT_AUTH:
+ allowed = 0;
+ break;
+ case PERMIT_LOCAL:
+ allowed = localhost;
+ break;
+ case PERMIT_OPEN:
+ allowed = 1;
+ break;
+ default:
+ assert(0);
+ allowed = 0;
+ }
+ }
+
+ if (allowed) {
+ switch(rx_command) {
+ case REQ_NULL:
+ /* Do nothing */
+ break;
+
+ case REQ_DUMP:
+ handle_dump(&rx_message, &tx_message);
+ break;
+
+ case REQ_ONLINE:
+ handle_online(&rx_message, &tx_message);
+ break;
+
+ case REQ_OFFLINE:
+ handle_offline(&rx_message, &tx_message);
+ break;
+
+ case REQ_BURST:
+ handle_burst(&rx_message, &tx_message);
+ break;
+
+ case REQ_MODIFY_MINPOLL:
+ handle_modify_minpoll(&rx_message, &tx_message);
+ break;
+
+ case REQ_MODIFY_MAXPOLL:
+ handle_modify_maxpoll(&rx_message, &tx_message);
+ break;
+
+ case REQ_MODIFY_MAXDELAY:
+ handle_modify_maxdelay(&rx_message, &tx_message);
+ break;
+
+ case REQ_MODIFY_MAXDELAYRATIO:
+ handle_modify_maxdelayratio(&rx_message, &tx_message);
+ break;
+
+ case REQ_MODIFY_MAXDELAYDEVRATIO:
+ handle_modify_maxdelaydevratio(&rx_message, &tx_message);
+ break;
+
+ case REQ_MODIFY_MAXUPDATESKEW:
+ handle_modify_maxupdateskew(&rx_message, &tx_message);
+ break;
+
+ case REQ_MODIFY_MAKESTEP:
+ handle_modify_makestep(&rx_message, &tx_message);
+ break;
+
+ case REQ_LOGON:
+ /* Authentication is no longer supported, log-on always fails */
+ tx_message.status = htons(STT_FAILED);
+ break;
+
+ case REQ_SETTIME:
+ handle_settime(&rx_message, &tx_message);
+ break;
+
+ case REQ_LOCAL2:
+ handle_local(&rx_message, &tx_message);
+ break;
+
+ case REQ_MANUAL:
+ handle_manual(&rx_message, &tx_message);
+ break;
+
+ case REQ_N_SOURCES:
+ handle_n_sources(&rx_message, &tx_message);
+ break;
+
+ case REQ_SOURCE_DATA:
+ handle_source_data(&rx_message, &tx_message);
+ break;
+
+ case REQ_REKEY:
+ handle_rekey(&rx_message, &tx_message);
+ break;
+
+ case REQ_ALLOW:
+ handle_allowdeny(&rx_message, &tx_message, 1, 0);
+ break;
+
+ case REQ_ALLOWALL:
+ handle_allowdeny(&rx_message, &tx_message, 1, 1);
+ break;
+
+ case REQ_DENY:
+ handle_allowdeny(&rx_message, &tx_message, 0, 0);
+ break;
+
+ case REQ_DENYALL:
+ handle_allowdeny(&rx_message, &tx_message, 0, 1);
+ break;
+
+ case REQ_CMDALLOW:
+ handle_cmdallowdeny(&rx_message, &tx_message, 1, 0);
+ break;
+
+ case REQ_CMDALLOWALL:
+ handle_cmdallowdeny(&rx_message, &tx_message, 1, 1);
+ break;
+
+ case REQ_CMDDENY:
+ handle_cmdallowdeny(&rx_message, &tx_message, 0, 0);
+ break;
+
+ case REQ_CMDDENYALL:
+ handle_cmdallowdeny(&rx_message, &tx_message, 0, 1);
+ break;
+
+ case REQ_ACCHECK:
+ handle_accheck(&rx_message, &tx_message);
+ break;
+
+ case REQ_CMDACCHECK:
+ handle_cmdaccheck(&rx_message, &tx_message);
+ break;
+
+ case REQ_ADD_SERVER3:
+ handle_add_source(NTP_SERVER, &rx_message, &tx_message);
+ break;
+
+ case REQ_ADD_PEER3:
+ handle_add_source(NTP_PEER, &rx_message, &tx_message);
+ break;
+
+ case REQ_DEL_SOURCE:
+ handle_del_source(&rx_message, &tx_message);
+ break;
+
+ case REQ_WRITERTC:
+ handle_writertc(&rx_message, &tx_message);
+ break;
+
+ case REQ_DFREQ:
+ handle_dfreq(&rx_message, &tx_message);
+ break;
+
+ case REQ_DOFFSET:
+ handle_doffset(&rx_message, &tx_message);
+ break;
+
+ case REQ_TRACKING:
+ 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;
+
+ case REQ_RTCREPORT:
+ handle_rtcreport(&rx_message, &tx_message);
+ break;
+
+ case REQ_TRIMRTC:
+ handle_trimrtc(&rx_message, &tx_message);
+ break;
+
+ case REQ_CYCLELOGS:
+ handle_cyclelogs(&rx_message, &tx_message);
+ break;
+
+ case REQ_CLIENT_ACCESSES_BY_INDEX2:
+ handle_client_accesses_by_index(&rx_message, &tx_message);
+ break;
+
+ case REQ_MANUAL_LIST:
+ handle_manual_list(&rx_message, &tx_message);
+ break;
+
+ case REQ_MANUAL_DELETE:
+ handle_manual_delete(&rx_message, &tx_message);
+ break;
+
+ case REQ_MAKESTEP:
+ handle_make_step(&rx_message, &tx_message);
+ break;
+
+ case REQ_ACTIVITY:
+ handle_activity(&rx_message, &tx_message);
+ break;
+
+ case REQ_RESELECTDISTANCE:
+ handle_reselect_distance(&rx_message, &tx_message);
+ break;
+
+ case REQ_RESELECT:
+ handle_reselect(&rx_message, &tx_message);
+ break;
+
+ case REQ_MODIFY_MINSTRATUM:
+ handle_modify_minstratum(&rx_message, &tx_message);
+ break;
+
+ case REQ_MODIFY_POLLTARGET:
+ handle_modify_polltarget(&rx_message, &tx_message);
+ break;
+
+ case REQ_REFRESH:
+ handle_refresh(&rx_message, &tx_message);
+ break;
+
+ case REQ_SERVER_STATS:
+ handle_server_stats(&rx_message, &tx_message);
+ break;
+
+ case REQ_NTP_DATA:
+ handle_ntp_data(&rx_message, &tx_message);
+ break;
+
+ case REQ_SHUTDOWN:
+ handle_shutdown(&rx_message, &tx_message);
+ break;
+
+ case REQ_ONOFFLINE:
+ handle_onoffline(&rx_message, &tx_message);
+ break;
+
+ default:
+ DEBUG_LOG("Unhandled command %d", rx_command);
+ tx_message.status = htons(STT_FAILED);
+ break;
+ }
+ } else {
+ tx_message.status = htons(STT_UNAUTH);
+ }
+ }
+
+ /* Transmit the response */
+ {
+ /* Include a simple way to lose one message in three to test resend */
+
+ static int do_it=1;
+
+ if (do_it) {
+ transmit_reply(&tx_message, &where_from);
+ }
+
+#if 0
+ do_it = ((do_it + 1) % 3);
+#endif
+ }
+}
+
+/* ================================================== */
+
+int
+CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
+ {
+ ADF_Status status;
+
+ if (allow) {
+ if (all) {
+ status = ADF_AllowAll(access_auth_table, ip_addr, subnet_bits);
+ } else {
+ status = ADF_Allow(access_auth_table, ip_addr, subnet_bits);
+ }
+ } else {
+ if (all) {
+ status = ADF_DenyAll(access_auth_table, ip_addr, subnet_bits);
+ } else {
+ status = ADF_Deny(access_auth_table, ip_addr, subnet_bits);
+ }
+ }
+
+ if (status == ADF_BADSUBNET) {
+ return 0;
+ } else if (status == ADF_SUCCESS) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* ================================================== */
+
+int
+CAM_CheckAccessRestriction(IPAddr *ip_addr)
+{
+ return ADF_IsAllowed(access_auth_table, ip_addr);
+}
+
+
+/* ================================================== */
+/* ================================================== */
diff --git a/cmdmon.h b/cmdmon.h
new file mode 100644
index 0000000..5b717d2
--- /dev/null
+++ b/cmdmon.h
@@ -0,0 +1,40 @@
+/*
+ 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.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Header file for the control and monitoring module in the software
+ */
+
+#ifndef GOT_CMDMON_H
+#define GOT_CMDMON_H
+
+#include "addressing.h"
+
+extern void CAM_Initialise(int family);
+
+extern void CAM_Finalise(void);
+
+extern void CAM_OpenUnixSocket(void);
+extern int CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all);
+extern int CAM_CheckAccessRestriction(IPAddr *ip_addr);
+
+#endif /* GOT_CMDMON_H */
diff --git a/cmdparse.c b/cmdparse.c
new file mode 100644
index 0000000..6fae81c
--- /dev/null
+++ b/cmdparse.c
@@ -0,0 +1,289 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow 1997-2003
+ * Copyright (C) Miroslav Lichvar 2013-2014, 2016
+ *
+ * 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.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Module for parsing various forms of directive and command lines that
+ are common to the configuration file and to the command client.
+
+ */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "cmdparse.h"
+#include "memory.h"
+#include "nameserv.h"
+#include "ntp.h"
+#include "util.h"
+
+/* ================================================== */
+
+int
+CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
+{
+ char *hostname, *cmd;
+ int n;
+
+ src->port = SRC_DEFAULT_PORT;
+ src->params.minpoll = SRC_DEFAULT_MINPOLL;
+ src->params.maxpoll = SRC_DEFAULT_MAXPOLL;
+ src->params.connectivity = SRC_ONLINE;
+ src->params.auto_offline = 0;
+ src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
+ src->params.burst = 0;
+ src->params.iburst = 0;
+ src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
+ src->params.poll_target = SRC_DEFAULT_POLLTARGET;
+ src->params.version = 0;
+ src->params.max_sources = SRC_DEFAULT_MAXSOURCES;
+ src->params.min_samples = SRC_DEFAULT_MINSAMPLES;
+ src->params.max_samples = SRC_DEFAULT_MAXSAMPLES;
+ src->params.filter_length = 0;
+ src->params.interleaved = 0;
+ src->params.sel_options = 0;
+ src->params.authkey = INACTIVE_AUTHKEY;
+ src->params.max_delay = SRC_DEFAULT_MAXDELAY;
+ src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
+ src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
+ src->params.min_delay = 0.0;
+ src->params.asymmetry = SRC_DEFAULT_ASYMMETRY;
+ src->params.offset = 0.0;
+
+ hostname = line;
+ line = CPS_SplitWord(line);
+
+ if (!*hostname)
+ return 0;
+
+ src->name = hostname;
+
+ /* Parse options */
+ for (; *line; line += n) {
+ cmd = line;
+ line = CPS_SplitWord(line);
+ n = 0;
+
+ if (!strcasecmp(cmd, "auto_offline")) {
+ src->params.auto_offline = 1;
+ } else if (!strcasecmp(cmd, "burst")) {
+ src->params.burst = 1;
+ } else if (!strcasecmp(cmd, "iburst")) {
+ src->params.iburst = 1;
+ } else if (!strcasecmp(cmd, "offline")) {
+ src->params.connectivity = SRC_OFFLINE;
+ } else if (!strcasecmp(cmd, "noselect")) {
+ src->params.sel_options |= SRC_SELECT_NOSELECT;
+ } else if (!strcasecmp(cmd, "prefer")) {
+ src->params.sel_options |= SRC_SELECT_PREFER;
+ } else if (!strcasecmp(cmd, "require")) {
+ src->params.sel_options |= SRC_SELECT_REQUIRE;
+ } else if (!strcasecmp(cmd, "trust")) {
+ src->params.sel_options |= SRC_SELECT_TRUST;
+ } else if (!strcasecmp(cmd, "key")) {
+ if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
+ src->params.authkey == INACTIVE_AUTHKEY)
+ return 0;
+ } else if (!strcasecmp(cmd, "asymmetry")) {
+ if (sscanf(line, "%lf%n", &src->params.asymmetry, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "filter")) {
+ if (sscanf(line, "%d%n", &src->params.filter_length, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "maxdelay")) {
+ if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "maxdelayratio")) {
+ if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "maxdelaydevratio")) {
+ if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "maxpoll")) {
+ if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "maxsamples")) {
+ if (sscanf(line, "%d%n", &src->params.max_samples, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "maxsources")) {
+ if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "mindelay")) {
+ if (sscanf(line, "%lf%n", &src->params.min_delay, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "minpoll")) {
+ if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "minsamples")) {
+ if (sscanf(line, "%d%n", &src->params.min_samples, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "minstratum")) {
+ if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "offset")) {
+ if (sscanf(line, "%lf%n", &src->params.offset, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "port")) {
+ if (sscanf(line, "%hu%n", &src->port, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "polltarget")) {
+ if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "presend")) {
+ if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "version")) {
+ if (sscanf(line, "%d%n", &src->params.version, &n) != 1)
+ return 0;
+ } else if (!strcasecmp(cmd, "xleave")) {
+ src->params.interleaved = 1;
+ } else {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* ================================================== */
+
+int
+CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance)
+{
+ int n;
+ char *cmd;
+
+ *stratum = 10;
+ *distance = 1.0;
+ *orphan = 0;
+
+ while (*line) {
+ cmd = line;
+ line = CPS_SplitWord(line);
+
+ if (!strcasecmp(cmd, "stratum")) {
+ if (sscanf(line, "%d%n", stratum, &n) != 1 ||
+ *stratum >= NTP_MAX_STRATUM || *stratum <= 0)
+ return 0;
+ } else if (!strcasecmp(cmd, "orphan")) {
+ *orphan = 1;
+ n = 0;
+ } else if (!strcasecmp(cmd, "distance")) {
+ if (sscanf(line, "%lf%n", distance, &n) != 1)
+ return 0;
+ } else {
+ return 0;
+ }
+
+ line += n;
+ }
+
+ return 1;
+}
+
+/* ================================================== */
+
+void
+CPS_NormalizeLine(char *line)
+{
+ char *p, *q;
+ int space = 1, first = 1;
+
+ /* Remove white-space at beginning and replace white-spaces with space char */
+ for (p = q = line; *p; p++) {
+ if (isspace((unsigned char)*p)) {
+ if (!space)
+ *q++ = ' ';
+ space = 1;
+ continue;
+ }
+
+ /* Discard comment lines */
+ if (first && strchr("!;#%", *p))
+ break;
+
+ *q++ = *p;
+ space = first = 0;
+ }
+
+ /* Strip trailing space */
+ if (q > line && q[-1] == ' ')
+ q--;
+
+ *q = '\0';
+}
+
+/* ================================================== */
+
+char *
+CPS_SplitWord(char *line)
+{
+ char *p = line, *q = line;
+
+ /* Skip white-space before the word */
+ while (*q && isspace((unsigned char)*q))
+ q++;
+
+ /* Move the word to the beginning */
+ while (*q && !isspace((unsigned char)*q))
+ *p++ = *q++;
+
+ /* Find the next word */
+ while (*q && isspace((unsigned char)*q))
+ q++;
+
+ *p = '\0';
+
+ /* Return pointer to the next word or NUL */
+ return q;
+}
+
+/* ================================================== */
+
+int
+CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key)
+{
+ char *s1, *s2, *s3, *s4;
+
+ s1 = line;
+ s2 = CPS_SplitWord(s1);
+ s3 = CPS_SplitWord(s2);
+ s4 = CPS_SplitWord(s3);
+
+ /* Require two or three words */
+ if (!*s2 || *s4)
+ return 0;
+
+ if (sscanf(s1, "%"SCNu32, id) != 1)
+ return 0;
+
+ if (*s3) {
+ *hash = s2;
+ *key = s3;
+ } else {
+ *hash = "MD5";
+ *key = s2;
+ }
+
+ return 1;
+}
diff --git a/cmdparse.h b/cmdparse.h
new file mode 100644
index 0000000..19f4bb7
--- /dev/null
+++ b/cmdparse.h
@@ -0,0 +1,54 @@
+/*
+ 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.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Header file for the command parser
+ */
+
+#ifndef GOT_CMDPARSE_H
+#define GOT_CMDPARSE_H
+
+#include "srcparams.h"
+#include "addressing.h"
+
+typedef struct {
+ char *name;
+ unsigned short port;
+ SourceParameters params;
+} CPS_NTP_Source;
+
+/* Parse a command to add an NTP server or peer */
+extern int CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
+
+/* Parse a command to enable local reference */
+extern int CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance);
+
+/* Remove extra white-space and comments */
+extern void CPS_NormalizeLine(char *line);
+
+/* Terminate first word and return pointer to the next word */
+extern char *CPS_SplitWord(char *line);
+
+/* Parse a key from keyfile */
+extern int CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key);
+
+#endif /* GOT_CMDPARSE_H */
diff --git a/conf.c b/conf.c
new file mode 100644
index 0000000..85a7f2e
--- /dev/null
+++ b/conf.c
@@ -0,0 +1,2036 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow 1997-2003
+ * Copyright (C) Miroslav Lichvar 2009-2017
+ *
+ * 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.
+ *
+ **********************************************************************
+
+ =======================================================================
+
+ Module that reads and processes the configuration file.
+ */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "array.h"
+#include "conf.h"
+#include "ntp_sources.h"
+#include "ntp_core.h"
+#include "refclock.h"
+#include "cmdmon.h"
+#include "srcparams.h"
+#include "logging.h"
+#include "nameserv.h"
+#include "memory.h"
+#include "cmdparse.h"
+#include "util.h"
+
+/* ================================================== */
+/* Forward prototypes */
+
+static int parse_string(char *line, char **result);
+static int parse_int(char *line, int *result);
+static int parse_double(char *line, double *result);
+static int parse_null(char *line);
+
+static void parse_allow_deny(char *line, ARR_Instance restrictions, int allow);
+static void parse_bindacqaddress(char *);
+static void parse_bindaddress(char *);
+static void parse_bindcmdaddress(char *);
+static void parse_broadcast(char *);
+static void parse_clientloglimit(char *);
+static void parse_fallbackdrift(char *);
+static void parse_hwtimestamp(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_ratelimit(char *line, int *enabled, int *interval,
+ int *burst, int *leak);
+static void parse_refclock(char *);
+static void parse_smoothtime(char *);
+static void parse_source(char *line, NTP_Source_Type type, int pool);
+static void parse_tempcomp(char *);
+
+/* ================================================== */
+/* Configuration variables */
+
+static int restarted = 0;
+static char *rtc_device;
+static int acquisition_port = -1;
+static int ntp_port = NTP_PORT;
+static char *keys_file = NULL;
+static char *drift_file = NULL;
+static char *rtc_file = NULL;
+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_drift = 500000.0; /* in ppm */
+static double max_slew_rate = 1e6 / 12.0; /* in ppm */
+
+static double max_distance = 3.0;
+static double max_jitter = 1.0;
+static double reselect_distance = 1e-4;
+static double stratum_weight = 1e-3;
+static double combine_limit = 3.0;
+
+static int cmd_port = DEFAULT_CANDM_PORT;
+
+static int raw_measurements = 0;
+static int do_log_measurements = 0;
+static int do_log_statistics = 0;
+static int do_log_tracking = 0;
+static int do_log_rtc = 0;
+static int do_log_refclocks = 0;
+static int do_log_tempcomp = 0;
+static int log_banner = 32;
+static char *logdir;
+static char *dumpdir;
+
+static int enable_local=0;
+static int local_stratum;
+static int local_orphan;
+static double local_distance;
+
+/* Threshold (in seconds) - if absolute value of initial error is less
+ than this, slew instead of stepping */
+static double init_slew_threshold;
+/* Array of IPAddr */
+static ARR_Instance init_sources;
+
+static int enable_manual=0;
+
+/* Flag set if the RTC runs UTC (default is it runs local time
+ incl. daylight saving). */
+static int rtc_on_utc = 0;
+
+/* Filename used to read the hwclock(8) LOCAL/UTC setting */
+static char *hwclock_file;
+
+/* Flag set if the RTC should be automatically synchronised by kernel */
+static int rtc_sync = 0;
+
+/* Limit and threshold for clock stepping */
+static int make_step_limit = 0;
+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;
+static int max_offset_ignore;
+static double max_offset;
+
+/* Maximum and minimum number of samples per source */
+static int max_samples = 0; /* no limit */
+static int min_samples = 6;
+
+/* Threshold for a time adjustment to be logged to syslog */
+static double log_change_threshold = 1.0;
+
+static char *mail_user_on_change = NULL;
+static double mail_change_threshold = 0.0;
+
+/* Flag indicating that we don't want to log clients, e.g. to save
+ memory */
+static int no_client_log = 0;
+
+/* Limit memory allocated for the clients log */
+static unsigned long client_log_limit = 524288;
+
+/* Minimum and maximum fallback drift intervals */
+static int fb_drift_min = 0;
+static int fb_drift_max = 0;
+
+/* IP addresses for binding the NTP server sockets to. UNSPEC family means
+ INADDR_ANY will be used */
+static IPAddr bind_address4, bind_address6;
+
+/* IP addresses for binding the NTP client sockets to. UNSPEC family means
+ INADDR_ANY will be used */
+static IPAddr bind_acq_address4, bind_acq_address6;
+
+/* IP addresses for binding the command socket to. UNSPEC family means
+ the loopback address will be used */
+static IPAddr bind_cmd_address4, bind_cmd_address6;
+
+/* Path to the Unix domain command socket. */
+static char *bind_cmd_path;
+
+/* Path to Samba (ntp_signd) socket. */
+static char *ntp_signd_socket = NULL;
+
+/* Filename to use for storing pid of running chronyd, to prevent multiple
+ * chronyds being started. */
+static char *pidfile;
+
+/* Rate limiting parameters */
+static int ntp_ratelimit_enabled = 0;
+static int ntp_ratelimit_interval = 3;
+static int ntp_ratelimit_burst = 8;
+static int ntp_ratelimit_leak = 2;
+static int cmd_ratelimit_enabled = 0;
+static int cmd_ratelimit_interval = -4;
+static int cmd_ratelimit_burst = 8;
+static int cmd_ratelimit_leak = 2;
+
+/* 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_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;
+
+/* Array of CNF_HwTsInterface */
+static ARR_Instance hwts_interfaces;
+
+typedef struct {
+ NTP_Source_Type type;
+ int pool;
+ CPS_NTP_Source params;
+} NTP_Source;
+
+/* Array of NTP_Source */
+static ARR_Instance ntp_sources;
+
+/* Array of RefclockParameters */
+static ARR_Instance refclock_sources;
+
+typedef struct _AllowDeny {
+ IPAddr ip;
+ int subnet_bits;
+ int all; /* 1 to override existing more specific defns */
+ int allow; /* 0 for deny, 1 for allow */
+} AllowDeny;
+
+/* Arrays of AllowDeny */
+static ARR_Instance ntp_restrictions;
+static ARR_Instance cmd_restrictions;
+
+typedef struct {
+ IPAddr addr;
+ unsigned short port;
+ int interval;
+} NTP_Broadcast_Destination;
+
+/* Array of NTP_Broadcast_Destination */
+static ARR_Instance broadcasts;
+
+/* ================================================== */
+
+/* The line number in the configuration file being processed */
+static int line_number;
+static const char *processed_file;
+static const char *processed_command;
+
+/* ================================================== */
+
+static void
+command_parse_error(void)
+{
+ LOG_FATAL("Could not parse %s directive at line %d%s%s",
+ processed_command, line_number, processed_file ? " in file " : "",
+ processed_file ? processed_file : "");
+}
+
+/* ================================================== */
+
+static void
+other_parse_error(const char *message)
+{
+ LOG_FATAL("%s at line %d%s%s",
+ message, line_number, processed_file ? " in file " : "",
+ processed_file ? processed_file : "");
+}
+
+/* ================================================== */
+
+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++;
+ for (; *line; line++) {
+ if (*line == ' ')
+ num++;
+ }
+
+ return num;
+}
+
+/* ================================================== */
+
+static void
+check_number_of_args(char *line, int num)
+{
+ num -= get_number_of_args(line);
+
+ if (num) {
+ LOG_FATAL("%s arguments for %s directive at line %d%s%s",
+ num > 0 ? "Missing" : "Too many",
+ processed_command, line_number, processed_file ? " in file " : "",
+ processed_file ? processed_file : "");
+ }
+}
+
+/* ================================================== */
+
+void
+CNF_Initialise(int r, int client_only)
+{
+ restarted = r;
+
+ hwts_interfaces = ARR_CreateInstance(sizeof (CNF_HwTsInterface));
+
+ 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("");
+ rtc_device = Strdup(DEFAULT_RTC_DEVICE);
+ hwclock_file = Strdup(DEFAULT_HWCLOCK_FILE);
+ user = Strdup(DEFAULT_USER);
+
+ if (client_only) {
+ cmd_port = ntp_port = 0;
+ bind_cmd_path = Strdup("");
+ pidfile = Strdup("");
+ } else {
+ bind_cmd_path = Strdup(DEFAULT_COMMAND_SOCKET);
+ pidfile = Strdup(DEFAULT_PID_FILE);
+ }
+}
+
+/* ================================================== */
+
+void
+CNF_Finalise(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARR_GetSize(hwts_interfaces); i++)
+ Free(((CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, i))->name);
+ ARR_DestroyInstance(hwts_interfaces);
+
+ 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(bind_cmd_path);
+ Free(ntp_signd_socket);
+ Free(pidfile);
+ Free(rtc_device);
+ Free(rtc_file);
+ Free(user);
+ Free(mail_user_on_change);
+ Free(tempcomp_sensor_file);
+ Free(tempcomp_point_file);
+}
+
+/* ================================================== */
+
+/* Read the configuration file */
+void
+CNF_ReadFile(const char *filename)
+{
+ FILE *in;
+ char line[2048];
+ int i;
+
+ in = fopen(filename, "r");
+ if (!in) {
+ LOG_FATAL("Could not open configuration file %s : %s",
+ filename, strerror(errno));
+ return;
+ }
+
+ DEBUG_LOG("Reading %s", filename);
+
+ for (i = 1; fgets(line, sizeof(line), in); i++) {
+ CNF_ParseLine(filename, i, line);
+ }
+
+ fclose(in);
+}
+
+/* ================================================== */
+
+/* Parse one configuration line */
+void
+CNF_ParseLine(const char *filename, int number, char *line)
+{
+ char *p, *command;
+
+ /* Set global variables used in error messages */
+ processed_file = filename;
+ line_number = number;
+
+ /* Remove extra white-space and comments */
+ CPS_NormalizeLine(line);
+
+ /* Skip blank lines */
+ if (!*line)
+ return;
+
+ /* We have a real line, now try to match commands */
+ processed_command = command = line;
+ p = CPS_SplitWord(line);
+
+ if (!strcasecmp(command, "acquisitionport")) {
+ parse_int(p, &acquisition_port);
+ } else if (!strcasecmp(command, "allow")) {
+ parse_allow_deny(p, ntp_restrictions, 1);
+ } else if (!strcasecmp(command, "bindacqaddress")) {
+ parse_bindacqaddress(p);
+ } else if (!strcasecmp(command, "bindaddress")) {
+ parse_bindaddress(p);
+ } else if (!strcasecmp(command, "bindcmdaddress")) {
+ parse_bindcmdaddress(p);
+ } else if (!strcasecmp(command, "broadcast")) {
+ parse_broadcast(p);
+ } else if (!strcasecmp(command, "clientloglimit")) {
+ parse_clientloglimit(p);
+ } else if (!strcasecmp(command, "cmdallow")) {
+ parse_allow_deny(p, cmd_restrictions, 1);
+ } else if (!strcasecmp(command, "cmddeny")) {
+ parse_allow_deny(p, cmd_restrictions, 0);
+ } else if (!strcasecmp(command, "cmdport")) {
+ parse_int(p, &cmd_port);
+ } else if (!strcasecmp(command, "cmdratelimit")) {
+ parse_ratelimit(p, &cmd_ratelimit_enabled, &cmd_ratelimit_interval,
+ &cmd_ratelimit_burst, &cmd_ratelimit_leak);
+ } else if (!strcasecmp(command, "combinelimit")) {
+ parse_double(p, &combine_limit);
+ } else if (!strcasecmp(command, "corrtimeratio")) {
+ parse_double(p, &correction_time_ratio);
+ } else if (!strcasecmp(command, "deny")) {
+ parse_allow_deny(p, ntp_restrictions, 0);
+ } else if (!strcasecmp(command, "driftfile")) {
+ parse_string(p, &drift_file);
+ } else if (!strcasecmp(command, "dumpdir")) {
+ parse_string(p, &dumpdir);
+ } else if (!strcasecmp(command, "dumponexit")) {
+ /* Silently ignored */
+ } else if (!strcasecmp(command, "fallbackdrift")) {
+ parse_fallbackdrift(p);
+ } else if (!strcasecmp(command, "hwclockfile")) {
+ parse_string(p, &hwclock_file);
+ } else if (!strcasecmp(command, "hwtimestamp")) {
+ parse_hwtimestamp(p);
+ } else if (!strcasecmp(command, "include")) {
+ parse_include(p);
+ } else if (!strcasecmp(command, "initstepslew")) {
+ 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, "local")) {
+ parse_local(p);
+ } else if (!strcasecmp(command, "lock_all")) {
+ lock_memory = parse_null(p);
+ } else if (!strcasecmp(command, "log")) {
+ parse_log(p);
+ } else if (!strcasecmp(command, "logbanner")) {
+ parse_int(p, &log_banner);
+ } else if (!strcasecmp(command, "logchange")) {
+ parse_double(p, &log_change_threshold);
+ } else if (!strcasecmp(command, "logdir")) {
+ parse_string(p, &logdir);
+ } else if (!strcasecmp(command, "mailonchange")) {
+ parse_mailonchange(p);
+ } else if (!strcasecmp(command, "makestep")) {
+ parse_makestep(p);
+ } else if (!strcasecmp(command, "manual")) {
+ enable_manual = parse_null(p);
+ } else if (!strcasecmp(command, "maxchange")) {
+ parse_maxchange(p);
+ } else if (!strcasecmp(command, "maxclockerror")) {
+ parse_double(p, &max_clock_error);
+ } else if (!strcasecmp(command, "maxdistance")) {
+ parse_double(p, &max_distance);
+ } else if (!strcasecmp(command, "maxdrift")) {
+ parse_double(p, &max_drift);
+ } else if (!strcasecmp(command, "maxjitter")) {
+ parse_double(p, &max_jitter);
+ } else if (!strcasecmp(command, "maxsamples")) {
+ parse_int(p, &max_samples);
+ } else if (!strcasecmp(command, "maxslewrate")) {
+ parse_double(p, &max_slew_rate);
+ } else if (!strcasecmp(command, "maxupdateskew")) {
+ 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, "ntpsigndsocket")) {
+ parse_string(p, &ntp_signd_socket);
+ } else if (!strcasecmp(command, "peer")) {
+ parse_source(p, NTP_PEER, 0);
+ } else if (!strcasecmp(command, "pidfile")) {
+ parse_string(p, &pidfile);
+ } else if (!strcasecmp(command, "pool")) {
+ parse_source(p, NTP_SERVER, 1);
+ } else if (!strcasecmp(command, "port")) {
+ parse_int(p, &ntp_port);
+ } else if (!strcasecmp(command, "ratelimit")) {
+ parse_ratelimit(p, &ntp_ratelimit_enabled, &ntp_ratelimit_interval,
+ &ntp_ratelimit_burst, &ntp_ratelimit_leak);
+ } else if (!strcasecmp(command, "refclock")) {
+ parse_refclock(p);
+ } else if (!strcasecmp(command, "reselectdist")) {
+ parse_double(p, &reselect_distance);
+ } else if (!strcasecmp(command, "rtcautotrim")) {
+ parse_double(p, &rtc_autotrim_threshold);
+ } else if (!strcasecmp(command, "rtcdevice")) {
+ parse_string(p, &rtc_device);
+ } else if (!strcasecmp(command, "rtcfile")) {
+ parse_string(p, &rtc_file);
+ } else if (!strcasecmp(command, "rtconutc")) {
+ rtc_on_utc = parse_null(p);
+ } else if (!strcasecmp(command, "rtcsync")) {
+ rtc_sync = parse_null(p);
+ } else if (!strcasecmp(command, "sched_priority")) {
+ parse_int(p, &sched_priority);
+ } else if (!strcasecmp(command, "server")) {
+ parse_source(p, NTP_SERVER, 0);
+ } else if (!strcasecmp(command, "smoothtime")) {
+ parse_smoothtime(p);
+ } else if (!strcasecmp(command, "stratumweight")) {
+ parse_double(p, &stratum_weight);
+ } else if (!strcasecmp(command, "tempcomp")) {
+ parse_tempcomp(p);
+ } else if (!strcasecmp(command, "user")) {
+ parse_string(p, &user);
+ } else if (!strcasecmp(command, "commandkey") ||
+ !strcasecmp(command, "generatecommandkey") ||
+ !strcasecmp(command, "linux_freq_scale") ||
+ !strcasecmp(command, "linux_hz")) {
+ LOG(LOGS_WARN, "%s directive is no longer supported", command);
+ } else {
+ other_parse_error("Invalid command");
+ }
+}
+
+/* ================================================== */
+
+static int
+parse_string(char *line, char **result)
+{
+ check_number_of_args(line, 1);
+ Free(*result);
+ *result = Strdup(line);
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+parse_int(char *line, int *result)
+{
+ check_number_of_args(line, 1);
+ if (sscanf(line, "%d", result) != 1) {
+ command_parse_error();
+ return 0;
+ }
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+parse_double(char *line, double *result)
+{
+ check_number_of_args(line, 1);
+ if (sscanf(line, "%lf", result) != 1) {
+ command_parse_error();
+ return 0;
+ }
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+parse_null(char *line)
+{
+ check_number_of_args(line, 0);
+ return 1;
+}
+
+/* ================================================== */
+
+static void
+parse_source(char *line, NTP_Source_Type type, int pool)
+{
+ NTP_Source source;
+
+ source.type = type;
+ source.pool = pool;
+
+ if (!CPS_ParseNTPSourceAdd(line, &source.params)) {
+ command_parse_error();
+ return;
+ }
+
+ source.params.name = Strdup(source.params.name);
+ ARR_AppendElement(ntp_sources, &source);
+}
+
+/* ================================================== */
+
+static void
+parse_ratelimit(char *line, int *enabled, int *interval, int *burst, int *leak)
+{
+ int n, val;
+ char *opt;
+
+ *enabled = 1;
+
+ while (*line) {
+ opt = line;
+ line = CPS_SplitWord(line);
+ if (sscanf(line, "%d%n", &val, &n) != 1) {
+ command_parse_error();
+ return;
+ }
+ line += n;
+ if (!strcasecmp(opt, "interval"))
+ *interval = val;
+ else if (!strcasecmp(opt, "burst"))
+ *burst = val;
+ else if (!strcasecmp(opt, "leak"))
+ *leak = val;
+ else
+ command_parse_error();
+ }
+}
+
+/* ================================================== */
+
+static void
+parse_refclock(char *line)
+{
+ int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples, sel_options;
+ int max_lock_age, pps_forced, stratum, tai;
+ uint32_t ref_id, lock_ref_id;
+ double offset, delay, precision, max_dispersion, pulse_width;
+ char *p, *cmd, *name, *param;
+ unsigned char ref[5];
+ RefclockParameters *refclock;
+
+ poll = 4;
+ dpoll = 0;
+ filter_length = 64;
+ pps_forced = 0;
+ pps_rate = 0;
+ min_samples = SRC_DEFAULT_MINSAMPLES;
+ max_samples = SRC_DEFAULT_MAXSAMPLES;
+ sel_options = 0;
+ offset = 0.0;
+ delay = 1e-9;
+ precision = 0.0;
+ max_dispersion = 0.0;
+ pulse_width = 0.0;
+ ref_id = 0;
+ max_lock_age = 2;
+ lock_ref_id = 0;
+ stratum = 0;
+ tai = 0;
+
+ if (!*line) {
+ command_parse_error();
+ return;
+ }
+
+ p = line;
+ line = CPS_SplitWord(line);
+
+ if (!*line) {
+ command_parse_error();
+ return;
+ }
+
+ name = Strdup(p);
+
+ p = line;
+ line = CPS_SplitWord(line);
+ param = Strdup(p);
+
+ for (cmd = line; *cmd; line += n, cmd = line) {
+ line = CPS_SplitWord(line);
+
+ if (!strcasecmp(cmd, "refid")) {
+ if (sscanf(line, "%4s%n", (char *)ref, &n) != 1)
+ break;
+ ref_id = (uint32_t)ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
+ } else if (!strcasecmp(cmd, "lock")) {
+ if (sscanf(line, "%4s%n", (char *)ref, &n) != 1)
+ break;
+ lock_ref_id = (uint32_t)ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
+ } else if (!strcasecmp(cmd, "poll")) {
+ if (sscanf(line, "%d%n", &poll, &n) != 1) {
+ break;
+ }
+ } else if (!strcasecmp(cmd, "dpoll")) {
+ if (sscanf(line, "%d%n", &dpoll, &n) != 1) {
+ break;
+ }
+ } else if (!strcasecmp(cmd, "filter")) {
+ if (sscanf(line, "%d%n", &filter_length, &n) != 1) {
+ break;
+ }
+ } 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, "maxlockage")) {
+ if (sscanf(line, "%d%n", &max_lock_age, &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;
+ } else if (!strcasecmp(cmd, "delay")) {
+ if (sscanf(line, "%lf%n", &delay, &n) != 1)
+ break;
+ } else if (!strcasecmp(cmd, "pps")) {
+ n = 0;
+ pps_forced = 1;
+ } else if (!strcasecmp(cmd, "precision")) {
+ if (sscanf(line, "%lf%n", &precision, &n) != 1)
+ break;
+ } else if (!strcasecmp(cmd, "maxdispersion")) {
+ if (sscanf(line, "%lf%n", &max_dispersion, &n) != 1)
+ break;
+ } else if (!strcasecmp(cmd, "stratum")) {
+ if (sscanf(line, "%d%n", &stratum, &n) != 1 ||
+ stratum >= NTP_MAX_STRATUM || stratum < 0)
+ break;
+ } else if (!strcasecmp(cmd, "tai")) {
+ n = 0;
+ tai = 1;
+ } else if (!strcasecmp(cmd, "width")) {
+ if (sscanf(line, "%lf%n", &pulse_width, &n) != 1)
+ break;
+ } else if (!strcasecmp(cmd, "noselect")) {
+ n = 0;
+ sel_options |= SRC_SELECT_NOSELECT;
+ } else if (!strcasecmp(cmd, "prefer")) {
+ n = 0;
+ sel_options |= SRC_SELECT_PREFER;
+ } else if (!strcasecmp(cmd, "trust")) {
+ n = 0;
+ sel_options |= SRC_SELECT_TRUST;
+ } else if (!strcasecmp(cmd, "require")) {
+ n = 0;
+ sel_options |= SRC_SELECT_REQUIRE;
+ } else {
+ other_parse_error("Invalid refclock option");
+ return;
+ }
+ }
+
+ if (*cmd) {
+ command_parse_error();
+ return;
+ }
+
+ 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_forced = pps_forced;
+ refclock->pps_rate = pps_rate;
+ refclock->min_samples = min_samples;
+ refclock->max_samples = max_samples;
+ refclock->sel_options = sel_options;
+ refclock->stratum = stratum;
+ refclock->tai = tai;
+ refclock->offset = offset;
+ refclock->delay = delay;
+ refclock->precision = precision;
+ refclock->max_dispersion = max_dispersion;
+ refclock->pulse_width = pulse_width;
+ refclock->ref_id = ref_id;
+ refclock->max_lock_age = max_lock_age;
+ refclock->lock_ref_id = lock_ref_id;
+}
+
+/* ================================================== */
+
+static void
+parse_log(char *line)
+{
+ char *log_name;
+ do {
+ log_name = line;
+ line = CPS_SplitWord(line);
+ if (*log_name) {
+ if (!strcmp(log_name, "rawmeasurements")) {
+ do_log_measurements = 1;
+ raw_measurements = 1;
+ } else if (!strcmp(log_name, "measurements")) {
+ do_log_measurements = 1;
+ } else if (!strcmp(log_name, "statistics")) {
+ do_log_statistics = 1;
+ } else if (!strcmp(log_name, "tracking")) {
+ do_log_tracking = 1;
+ } else if (!strcmp(log_name, "rtc")) {
+ do_log_rtc = 1;
+ } else if (!strcmp(log_name, "refclocks")) {
+ do_log_refclocks = 1;
+ } else if (!strcmp(log_name, "tempcomp")) {
+ do_log_tempcomp = 1;
+ } else {
+ other_parse_error("Invalid log parameter");
+ break;
+ }
+ } else {
+ break;
+ }
+ } while (1);
+}
+
+/* ================================================== */
+
+static void
+parse_local(char *line)
+{
+ if (!CPS_ParseLocal(line, &local_stratum, &local_orphan, &local_distance))
+ command_parse_error();
+ enable_local = 1;
+}
+
+/* ================================================== */
+
+static void
+parse_initstepslew(char *line)
+{
+ char *p, *hostname;
+ IPAddr ip_addr;
+
+ /* Ignore the line if chronyd was started with -R. */
+ if (restarted) {
+ return;
+ }
+
+ ARR_SetSize(init_sources, 0);
+ p = CPS_SplitWord(line);
+
+ if (sscanf(line, "%lf", &init_slew_threshold) != 1) {
+ command_parse_error();
+ return;
+ }
+
+ while (*p) {
+ hostname = p;
+ p = CPS_SplitWord(p);
+ if (*hostname) {
+ if (DNS_Name2IPAddress(hostname, &ip_addr, 1) == DNS_Success) {
+ ARR_AppendElement(init_sources, &ip_addr);
+ } else {
+ LOG(LOGS_WARN, "Could not resolve address of initstepslew server %s", hostname);
+ }
+ }
+ }
+}
+
+/* ================================================== */
+
+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);
+ if (sscanf(line, "%lu", &client_log_limit) != 1) {
+ command_parse_error();
+ }
+}
+
+/* ================================================== */
+
+static void
+parse_fallbackdrift(char *line)
+{
+ check_number_of_args(line, 2);
+ if (sscanf(line, "%d %d", &fb_drift_min, &fb_drift_max) != 2) {
+ command_parse_error();
+ }
+}
+
+/* ================================================== */
+
+static void
+parse_makestep(char *line)
+{
+ check_number_of_args(line, 2);
+ if (sscanf(line, "%lf %d", &make_step_threshold, &make_step_limit) != 2) {
+ make_step_limit = 0;
+ command_parse_error();
+ }
+
+ /* Disable limited makestep if chronyd was started with -R. */
+ if (restarted && make_step_limit > 0) {
+ make_step_limit = 0;
+ }
+}
+
+/* ================================================== */
+
+static void
+parse_maxchange(char *line)
+{
+ check_number_of_args(line, 3);
+ if (sscanf(line, "%lf %d %d", &max_offset, &max_offset_delay, &max_offset_ignore) != 3) {
+ max_offset_delay = -1;
+ command_parse_error();
+ }
+}
+
+/* ================================================== */
+
+static void
+parse_mailonchange(char *line)
+{
+ char *address;
+ 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);
+ } else {
+ mail_user_on_change = NULL;
+ command_parse_error();
+ }
+}
+
+/* ================================================== */
+
+static void
+parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
+{
+ char *p;
+ unsigned long a, b, c, d, n;
+ int all = 0;
+ AllowDeny *new_node = NULL;
+ IPAddr ip_addr;
+
+ p = line;
+
+ if (!strncmp(p, "all", 3)) {
+ all = 1;
+ p = CPS_SplitWord(line);
+ }
+
+ if (!*p) {
+ /* Empty line applies to all addresses */
+ new_node = (AllowDeny *)ARR_GetNewElement(restrictions);
+ new_node->allow = allow;
+ new_node->all = all;
+ new_node->ip.family = IPADDR_UNSPEC;
+ new_node->subnet_bits = 0;
+ } else {
+ char *slashpos;
+ slashpos = strchr(p, '/');
+ if (slashpos) *slashpos = 0;
+
+ check_number_of_args(p, 1);
+ n = 0;
+ if (UTI_StringToIP(p, &ip_addr) ||
+ (n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) >= 1) {
+ new_node = (AllowDeny *)ARR_GetNewElement(restrictions);
+ new_node->allow = allow;
+ new_node->all = all;
+
+ if (n == 0) {
+ new_node->ip = ip_addr;
+ if (ip_addr.family == IPADDR_INET6)
+ new_node->subnet_bits = 128;
+ else
+ new_node->subnet_bits = 32;
+ } else {
+ new_node->ip.family = IPADDR_INET4;
+
+ a &= 0xff;
+ b &= 0xff;
+ c &= 0xff;
+ d &= 0xff;
+
+ switch (n) {
+ case 1:
+ new_node->ip.addr.in4 = (a<<24);
+ new_node->subnet_bits = 8;
+ break;
+ case 2:
+ new_node->ip.addr.in4 = (a<<24) | (b<<16);
+ new_node->subnet_bits = 16;
+ break;
+ case 3:
+ new_node->ip.addr.in4 = (a<<24) | (b<<16) | (c<<8);
+ new_node->subnet_bits = 24;
+ break;
+ case 4:
+ new_node->ip.addr.in4 = (a<<24) | (b<<16) | (c<<8) | d;
+ new_node->subnet_bits = 32;
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ if (slashpos) {
+ int specified_subnet_bits, n;
+ n = sscanf(slashpos+1, "%d", &specified_subnet_bits);
+ if (n == 1) {
+ new_node->subnet_bits = specified_subnet_bits;
+ } else {
+ command_parse_error();
+ }
+ }
+
+ } else {
+ if (!slashpos && 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;
+ if (ip_addr.family == IPADDR_INET6)
+ new_node->subnet_bits = 128;
+ else
+ new_node->subnet_bits = 32;
+ } else {
+ command_parse_error();
+ }
+ }
+ }
+}
+
+/* ================================================== */
+
+static void
+parse_bindacqaddress(char *line)
+{
+ IPAddr ip;
+
+ check_number_of_args(line, 1);
+ if (UTI_StringToIP(line, &ip)) {
+ if (ip.family == IPADDR_INET4)
+ bind_acq_address4 = ip;
+ else if (ip.family == IPADDR_INET6)
+ bind_acq_address6 = ip;
+ } else {
+ command_parse_error();
+ }
+}
+
+/* ================================================== */
+
+static void
+parse_bindaddress(char *line)
+{
+ IPAddr ip;
+
+ check_number_of_args(line, 1);
+ if (UTI_StringToIP(line, &ip)) {
+ if (ip.family == IPADDR_INET4)
+ bind_address4 = ip;
+ else if (ip.family == IPADDR_INET6)
+ bind_address6 = ip;
+ } else {
+ command_parse_error();
+ }
+}
+
+/* ================================================== */
+
+static void
+parse_bindcmdaddress(char *line)
+{
+ IPAddr ip;
+
+ check_number_of_args(line, 1);
+
+ /* Address starting with / is for the Unix domain socket */
+ if (line[0] == '/') {
+ parse_string(line, &bind_cmd_path);
+ /* / disables the socket */
+ if (!strcmp(bind_cmd_path, "/"))
+ bind_cmd_path[0] = '\0';
+ } else if (UTI_StringToIP(line, &ip)) {
+ if (ip.family == IPADDR_INET4)
+ bind_cmd_address4 = ip;
+ else if (ip.family == IPADDR_INET6)
+ bind_cmd_address6 = ip;
+ } else {
+ command_parse_error();
+ }
+}
+
+/* ================================================== */
+
+static void
+parse_broadcast(char *line)
+{
+ /* Syntax : broadcast <interval> <broadcast-IP-addr> [<port>] */
+ NTP_Broadcast_Destination *destination;
+ int port;
+ int interval;
+ char *p;
+ IPAddr ip;
+
+ p = line;
+ line = CPS_SplitWord(line);
+
+ if (sscanf(p, "%d", &interval) != 1) {
+ command_parse_error();
+ return;
+ }
+
+ p = line;
+ line = CPS_SplitWord(line);
+
+ if (!UTI_StringToIP(p, &ip)) {
+ command_parse_error();
+ return;
+ }
+
+ p = line;
+ line = CPS_SplitWord(line);
+
+ if (*p) {
+ if (sscanf(p, "%d", &port) != 1 || *line) {
+ command_parse_error();
+ return;
+ }
+ } else {
+ /* default port */
+ port = NTP_PORT;
+ }
+
+ destination = (NTP_Broadcast_Destination *)ARR_GetNewElement(broadcasts);
+ destination->addr = ip;
+ destination->port = port;
+ destination->interval = interval;
+}
+
+/* ================================================== */
+
+static void
+parse_smoothtime(char *line)
+{
+ if (get_number_of_args(line) != 3)
+ check_number_of_args(line, 2);
+
+ if (sscanf(line, "%lf %lf", &smooth_max_freq, &smooth_max_wander) != 2) {
+ smooth_max_freq = 0.0;
+ command_parse_error();
+ }
+
+ line = CPS_SplitWord(CPS_SplitWord(line));
+ smooth_leap_only = 0;
+
+ if (*line) {
+ if (!strcasecmp(line, "leaponly"))
+ smooth_leap_only = 1;
+ else
+ command_parse_error();
+ }
+}
+
+/* ================================================== */
+static void
+parse_tempcomp(char *line)
+{
+ char *p;
+ int point_form;
+
+ point_form = get_number_of_args(line) == 3;
+
+ if (!point_form)
+ check_number_of_args(line, 6);
+
+ p = line;
+ line = CPS_SplitWord(line);
+
+ if (!*p) {
+ 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;
+ }
+
+ Free(tempcomp_sensor_file);
+ tempcomp_sensor_file = Strdup(p);
+}
+
+/* ================================================== */
+
+static void
+parse_hwtimestamp(char *line)
+{
+ CNF_HwTsInterface *iface;
+ char *p, filter[5];
+ int n;
+
+ if (!*line) {
+ command_parse_error();
+ return;
+ }
+
+ p = line;
+ line = CPS_SplitWord(line);
+
+ iface = ARR_GetNewElement(hwts_interfaces);
+ iface->name = Strdup(p);
+ iface->minpoll = 0;
+ iface->min_samples = 2;
+ iface->max_samples = 16;
+ iface->nocrossts = 0;
+ iface->rxfilter = CNF_HWTS_RXFILTER_ANY;
+ iface->precision = 100.0e-9;
+ iface->tx_comp = 0.0;
+ iface->rx_comp = 0.0;
+
+ for (p = line; *p; line += n, p = line) {
+ line = CPS_SplitWord(line);
+
+ if (!strcasecmp(p, "maxsamples")) {
+ if (sscanf(line, "%d%n", &iface->max_samples, &n) != 1)
+ break;
+ } else if (!strcasecmp(p, "minpoll")) {
+ if (sscanf(line, "%d%n", &iface->minpoll, &n) != 1)
+ break;
+ } else if (!strcasecmp(p, "minsamples")) {
+ if (sscanf(line, "%d%n", &iface->min_samples, &n) != 1)
+ break;
+ } else if (!strcasecmp(p, "precision")) {
+ if (sscanf(line, "%lf%n", &iface->precision, &n) != 1)
+ break;
+ } else if (!strcasecmp(p, "rxcomp")) {
+ if (sscanf(line, "%lf%n", &iface->rx_comp, &n) != 1)
+ break;
+ } else if (!strcasecmp(p, "txcomp")) {
+ if (sscanf(line, "%lf%n", &iface->tx_comp, &n) != 1)
+ break;
+ } else if (!strcasecmp(p, "rxfilter")) {
+ if (sscanf(line, "%4s%n", filter, &n) != 1)
+ break;
+ if (!strcasecmp(filter, "none"))
+ iface->rxfilter = CNF_HWTS_RXFILTER_NONE;
+ else if (!strcasecmp(filter, "ntp"))
+ iface->rxfilter = CNF_HWTS_RXFILTER_NTP;
+ else if (!strcasecmp(filter, "all"))
+ iface->rxfilter = CNF_HWTS_RXFILTER_ALL;
+ else
+ break;
+ } else if (!strcasecmp(p, "nocrossts")) {
+ n = 0;
+ iface->nocrossts = 1;
+ } else {
+ break;
+ }
+ }
+
+ if (*p)
+ command_parse_error();
+}
+
+/* ================================================== */
+
+static void
+parse_include(char *line)
+{
+ glob_t gl;
+ size_t i;
+ int r;
+
+ check_number_of_args(line, 1);
+
+ if ((r = glob(line,
+#ifdef GLOB_NOMAGIC
+ GLOB_NOMAGIC |
+#endif
+ GLOB_ERR, NULL, &gl)) != 0) {
+ if (r != GLOB_NOMATCH)
+ LOG_FATAL("Could not search for files matching %s", line);
+
+ DEBUG_LOG("glob of %s failed", line);
+ return;
+ }
+
+ for (i = 0; i < gl.gl_pathc; i++)
+ CNF_ReadFile(gl.gl_pathv[i]);
+
+ globfree(&gl);
+}
+
+/* ================================================== */
+
+void
+CNF_CreateDirs(uid_t uid, gid_t gid)
+{
+ char *dir;
+
+ /* Create a directory for the Unix domain command socket */
+ if (bind_cmd_path[0]) {
+ dir = UTI_PathToDir(bind_cmd_path);
+ UTI_CreateDirAndParents(dir, 0770, uid, gid);
+
+ /* Check the permissions and owner/group in case the directory already
+ existed. It MUST NOT be accessible by others as permissions on Unix
+ domain sockets are ignored on some systems (e.g. Solaris). */
+ if (!UTI_CheckDirPermissions(dir, 0770, uid, gid)) {
+ LOG(LOGS_WARN, "Disabled command socket %s", bind_cmd_path);
+ bind_cmd_path[0] = '\0';
+ }
+
+ Free(dir);
+ }
+
+ if (logdir[0])
+ UTI_CreateDirAndParents(logdir, 0755, uid, gid);
+ if (dumpdir[0])
+ UTI_CreateDirAndParents(dumpdir, 0755, uid, gid);
+}
+
+/* ================================================== */
+
+void
+CNF_AddInitSources(void)
+{
+ CPS_NTP_Source cps_source;
+ NTP_Remote_Address ntp_addr;
+ char dummy_hostname[2] = "H";
+ unsigned int 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 = *(IPAddr *)ARR_GetElement(init_sources, i);
+ ntp_addr.port = cps_source.port;
+ cps_source.params.iburst = 1;
+ cps_source.params.connectivity = SRC_OFFLINE;
+
+ NSR_AddSource(&ntp_addr, NTP_SERVER, &cps_source.params);
+ }
+
+ ARR_SetSize(init_sources, 0);
+}
+
+/* ================================================== */
+
+void
+CNF_AddSources(void)
+{
+ NTP_Source *source;
+ unsigned int i;
+
+ 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)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARR_GetSize(refclock_sources); i++) {
+ RCL_AddRefclock((RefclockParameters *)ARR_GetElement(refclock_sources, i));
+ }
+
+ ARR_SetSize(refclock_sources, 0);
+}
+
+/* ================================================== */
+
+void
+CNF_AddBroadcasts(void)
+{
+ 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);
+}
+
+/* ================================================== */
+
+int
+CNF_GetNTPPort(void)
+{
+ return ntp_port;
+}
+
+/* ================================================== */
+
+int
+CNF_GetAcquisitionPort(void)
+{
+ return acquisition_port;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetDriftFile(void)
+{
+ return drift_file;
+}
+
+/* ================================================== */
+
+int
+CNF_GetLogBanner(void)
+{
+ return log_banner;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetLogDir(void)
+{
+ return logdir;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetDumpDir(void)
+{
+ return dumpdir;
+}
+
+/* ================================================== */
+
+int
+CNF_GetLogMeasurements(int *raw)
+{
+ *raw = raw_measurements;
+ return do_log_measurements;
+}
+
+/* ================================================== */
+
+int
+CNF_GetLogStatistics(void)
+{
+ return do_log_statistics;
+}
+
+/* ================================================== */
+
+int
+CNF_GetLogTracking(void)
+{
+ return do_log_tracking;
+}
+
+/* ================================================== */
+
+int
+CNF_GetLogRtc(void)
+{
+ return do_log_rtc;
+}
+
+/* ================================================== */
+
+int
+CNF_GetLogRefclocks(void)
+{
+ return do_log_refclocks;
+}
+
+/* ================================================== */
+
+int
+CNF_GetLogTempComp(void)
+{
+ return do_log_tempcomp;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetKeysFile(void)
+{
+ return keys_file;
+}
+
+/* ================================================== */
+
+double
+CNF_GetRtcAutotrim(void)
+{
+ return rtc_autotrim_threshold;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetRtcFile(void)
+{
+ return rtc_file;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetRtcDevice(void)
+{
+ return rtc_device;
+}
+
+/* ================================================== */
+
+double
+CNF_GetMaxUpdateSkew(void)
+{
+ return max_update_skew;
+}
+
+/* ================================================== */
+
+double
+CNF_GetMaxDrift(void)
+{
+ return max_drift;
+}
+
+/* ================================================== */
+
+double
+CNF_GetMaxClockError(void)
+{
+ return max_clock_error;
+}
+
+/* ================================================== */
+
+double
+CNF_GetCorrectionTimeRatio(void)
+{
+ return correction_time_ratio;
+}
+
+/* ================================================== */
+
+double
+CNF_GetMaxSlewRate(void)
+{
+ return max_slew_rate;
+}
+
+/* ================================================== */
+
+double
+CNF_GetMaxDistance(void)
+{
+ return max_distance;
+}
+
+/* ================================================== */
+
+double
+CNF_GetMaxJitter(void)
+{
+ return max_jitter;
+}
+
+/* ================================================== */
+
+double
+CNF_GetReselectDistance(void)
+{
+ return reselect_distance;
+}
+
+/* ================================================== */
+
+double
+CNF_GetStratumWeight(void)
+{
+ return stratum_weight;
+}
+
+/* ================================================== */
+
+double
+CNF_GetCombineLimit(void)
+{
+ return combine_limit;
+}
+
+/* ================================================== */
+
+int
+CNF_GetManualEnabled(void)
+{
+ return enable_manual;
+}
+
+/* ================================================== */
+
+int
+CNF_GetCommandPort(void) {
+ return cmd_port;
+}
+
+/* ================================================== */
+
+int
+CNF_AllowLocalReference(int *stratum, int *orphan, double *distance)
+{
+ if (enable_local) {
+ *stratum = local_stratum;
+ *orphan = local_orphan;
+ *distance = local_distance;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* ================================================== */
+
+int
+CNF_GetRtcOnUtc(void)
+{
+ return rtc_on_utc;
+}
+
+/* ================================================== */
+
+int
+CNF_GetRtcSync(void)
+{
+ return rtc_sync;
+}
+
+/* ================================================== */
+
+void
+CNF_GetMakeStep(int *limit, double *threshold)
+{
+ *limit = make_step_limit;
+ *threshold = make_step_threshold;
+}
+
+/* ================================================== */
+
+void
+CNF_GetMaxChange(int *delay, int *ignore, double *offset)
+{
+ *delay = max_offset_delay;
+ *ignore = max_offset_ignore;
+ *offset = max_offset;
+}
+
+/* ================================================== */
+
+double
+CNF_GetLogChange(void)
+{
+ return log_change_threshold;
+}
+
+/* ================================================== */
+
+void
+CNF_GetMailOnChange(int *enabled, double *threshold, char **user)
+{
+ if (mail_user_on_change) {
+ *enabled = 1;
+ *threshold = mail_change_threshold;
+ *user = mail_user_on_change;
+ } else {
+ *enabled = 0;
+ *threshold = 0.0;
+ *user = NULL;
+ }
+}
+
+/* ================================================== */
+
+void
+CNF_SetupAccessRestrictions(void)
+{
+ AllowDeny *node;
+ int status;
+ unsigned int i;
+
+ 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("Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
+ }
+ }
+
+ 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("Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
+ }
+ }
+
+ ARR_SetSize(ntp_restrictions, 0);
+ ARR_SetSize(cmd_restrictions, 0);
+}
+
+/* ================================================== */
+
+int
+CNF_GetNoClientLog(void)
+{
+ return no_client_log;
+}
+
+/* ================================================== */
+
+unsigned long
+CNF_GetClientLogLimit(void)
+{
+ return client_log_limit;
+}
+
+/* ================================================== */
+
+void
+CNF_GetFallbackDrifts(int *min, int *max)
+{
+ *min = fb_drift_min;
+ *max = fb_drift_max;
+}
+
+/* ================================================== */
+
+void
+CNF_GetBindAddress(int family, IPAddr *addr)
+{
+ if (family == IPADDR_INET4)
+ *addr = bind_address4;
+ else if (family == IPADDR_INET6)
+ *addr = bind_address6;
+ else
+ addr->family = IPADDR_UNSPEC;
+}
+
+/* ================================================== */
+
+void
+CNF_GetBindAcquisitionAddress(int family, IPAddr *addr)
+{
+ if (family == IPADDR_INET4)
+ *addr = bind_acq_address4;
+ else if (family == IPADDR_INET6)
+ *addr = bind_acq_address6;
+ else
+ addr->family = IPADDR_UNSPEC;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetBindCommandPath(void)
+{
+ return bind_cmd_path;
+}
+
+/* ================================================== */
+
+void
+CNF_GetBindCommandAddress(int family, IPAddr *addr)
+{
+ if (family == IPADDR_INET4)
+ *addr = bind_cmd_address4;
+ else if (family == IPADDR_INET6)
+ *addr = bind_cmd_address6;
+ else
+ addr->family = IPADDR_UNSPEC;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetNtpSigndSocket(void)
+{
+ return ntp_signd_socket;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetPidFile(void)
+{
+ return pidfile;
+}
+
+/* ================================================== */
+
+REF_LeapMode
+CNF_GetLeapSecMode(void)
+{
+ return leapsec_mode;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetLeapSecTimezone(void)
+{
+ return leapsec_tz;
+}
+
+/* ================================================== */
+
+int
+CNF_GetSchedPriority(void)
+{
+ return sched_priority;
+}
+
+/* ================================================== */
+
+int
+CNF_GetLockMemory(void)
+{
+ return lock_memory;
+}
+
+/* ================================================== */
+
+int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak)
+{
+ *interval = ntp_ratelimit_interval;
+ *burst = ntp_ratelimit_burst;
+ *leak = ntp_ratelimit_leak;
+ return ntp_ratelimit_enabled;
+}
+
+/* ================================================== */
+
+int CNF_GetCommandRateLimit(int *interval, int *burst, int *leak)
+{
+ *interval = cmd_ratelimit_interval;
+ *burst = cmd_ratelimit_burst;
+ *leak = cmd_ratelimit_leak;
+ return cmd_ratelimit_enabled;
+}
+
+/* ================================================== */
+
+void
+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_sensor_file;
+ *point_file = tempcomp_point_file;
+ *interval = tempcomp_interval;
+ *T0 = tempcomp_T0;
+ *k0 = tempcomp_k0;
+ *k1 = tempcomp_k1;
+ *k2 = tempcomp_k2;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetUser(void)
+{
+ return user;
+}
+
+/* ================================================== */
+
+int
+CNF_GetMaxSamples(void)
+{
+ return max_samples;
+}
+
+/* ================================================== */
+
+int
+CNF_GetMinSamples(void)
+{
+ return min_samples;
+}
+
+/* ================================================== */
+
+int
+CNF_GetMinSources(void)
+{
+ return min_sources;
+}
+
+/* ================================================== */
+
+char *
+CNF_GetHwclockFile(void)
+{
+ return hwclock_file;
+}
+
+/* ================================================== */
+
+int
+CNF_GetInitSources(void)
+{
+ return ARR_GetSize(init_sources);
+}
+
+/* ================================================== */
+
+double
+CNF_GetInitStepThreshold(void)
+{
+ return init_slew_threshold;
+}
+
+/* ================================================== */
+
+int
+CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface)
+{
+ if (index >= ARR_GetSize(hwts_interfaces))
+ return 0;
+
+ *iface = (CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, index);
+ return 1;
+}
diff --git a/conf.h b/conf.h
new file mode 100644
index 0000000..43217fc
--- /dev/null
+++ b/conf.h
@@ -0,0 +1,142 @@
+/*
+ chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow 1997-2003
+ * 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
+ * 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 configuration module
+ */
+
+#ifndef GOT_CONF_H
+#define GOT_CONF_H
+
+#include "addressing.h"
+#include "reference.h"
+
+extern void CNF_Initialise(int restarted, int client_only);
+extern void CNF_Finalise(void);
+
+extern char *CNF_GetRtcDevice(void);
+
+extern void CNF_ReadFile(const char *filename);
+extern void CNF_ParseLine(const char *filename, int number, char *line);
+
+extern void CNF_CreateDirs(uid_t uid, gid_t gid);
+
+extern void CNF_AddInitSources(void);
+extern void CNF_AddSources(void);
+extern void CNF_AddBroadcasts(void);
+extern void CNF_AddRefclocks(void);
+
+extern int CNF_GetAcquisitionPort(void);
+extern int CNF_GetNTPPort(void);
+extern char *CNF_GetDriftFile(void);
+extern char *CNF_GetLogDir(void);
+extern char *CNF_GetDumpDir(void);
+extern int CNF_GetLogBanner(void);
+extern int CNF_GetLogMeasurements(int *raw);
+extern int CNF_GetLogStatistics(void);
+extern int CNF_GetLogTracking(void);
+extern int CNF_GetLogRtc(void);
+extern int CNF_GetLogRefclocks(void);
+extern int CNF_GetLogTempComp(void);
+extern char *CNF_GetKeysFile(void);
+extern char *CNF_GetRtcFile(void);
+extern int CNF_GetManualEnabled(void);
+extern int CNF_GetCommandPort(void);
+extern int CNF_GetRtcOnUtc(void);
+extern int CNF_GetRtcSync(void);
+extern void CNF_GetMakeStep(int *limit, double *threshold);
+extern void CNF_GetMaxChange(int *delay, int *ignore, double *offset);
+extern double CNF_GetLogChange(void);
+extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user);
+extern int CNF_GetNoClientLog(void);
+extern unsigned long CNF_GetClientLogLimit(void);
+extern void CNF_GetFallbackDrifts(int *min, int *max);
+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_GetBindCommandPath(void);
+extern char *CNF_GetNtpSigndSocket(void);
+extern char *CNF_GetPidFile(void);
+extern REF_LeapMode CNF_GetLeapSecMode(void);
+extern char *CNF_GetLeapSecTimezone(void);
+
+/* Value returned in ppm, as read from file */
+extern double CNF_GetMaxUpdateSkew(void);
+extern double CNF_GetMaxClockError(void);
+extern double CNF_GetMaxDrift(void);
+extern double CNF_GetCorrectionTimeRatio(void);
+extern double CNF_GetMaxSlewRate(void);
+
+extern double CNF_GetMaxDistance(void);
+extern double CNF_GetMaxJitter(void);
+extern double CNF_GetReselectDistance(void);
+extern double CNF_GetStratumWeight(void);
+extern double CNF_GetCombineLimit(void);
+
+extern int CNF_AllowLocalReference(int *stratum, int *orphan, double *distance);
+
+extern void CNF_SetupAccessRestrictions(void);
+
+extern int CNF_GetSchedPriority(void);
+extern int CNF_GetLockMemory(void);
+
+extern int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak);
+extern int CNF_GetCommandRateLimit(int *interval, int *burst, int *leak);
+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);
+
+extern int CNF_GetInitSources(void);
+extern double CNF_GetInitStepThreshold(void);
+
+typedef enum {
+ CNF_HWTS_RXFILTER_ANY,
+ CNF_HWTS_RXFILTER_NONE,
+ CNF_HWTS_RXFILTER_NTP,
+ CNF_HWTS_RXFILTER_ALL,
+} CNF_HwTs_RxFilter;
+
+typedef struct {
+ char *name;
+ int minpoll;
+ int min_samples;
+ int max_samples;
+ int nocrossts;
+ CNF_HwTs_RxFilter rxfilter;
+ double precision;
+ double tx_comp;
+ double rx_comp;
+} CNF_HwTsInterface;
+
+extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
+
+#endif /* GOT_CONF_H */
diff --git a/configure b/configure
new file mode 100755
index 0000000..486b0bc
--- /dev/null
+++ b/configure
@@ -0,0 +1,1007 @@
+#!/bin/sh
+# =======================================================================
+#
+# chronyd/chronyc - Programs for keeping computer clocks accurate.
+#
+# Copyright (C) Richard P. Curnow 1997-2003
+# Copyright (C) Bryan Christianson 2016
+# Copyright (C) Miroslav Lichvar 2009, 2012-2018
+#
+# =======================================================================
+
+# This configure script determines the operating system type and version
+
+# ======================================================================
+# FUNCTIONS
+
+#{{{ test_code
+test_code () {
+ name=$1
+ headers=$2
+ cflags=$3
+ ldflags=$4
+ code=$5
+
+ printf "%s" "Checking for $name : "
+
+ (
+ echo "#include \"config.h\""
+ for h in $headers; do
+ echo "#include <$h>"
+ done
+ echo "int main(int argc, char **argv) {"
+ echo "$code"
+ echo "return 0; }"
+ ) > docheck.c
+
+ echo "docheck.c:" >> config.log
+ cat docheck.c >> config.log
+ echo $MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o docheck docheck.c $ldflags \
+ $MYLDFLAGS >> config.log
+ $MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o docheck docheck.c $ldflags \
+ $MYLDFLAGS >> config.log 2>&1
+
+ if [ $? -eq 0 ]
+ then
+ echo "Yes"
+ result=0
+ else
+ echo "No"
+ result=1
+ fi
+ rm -f docheck.c docheck
+ echo >> config.log
+ return $result
+}
+#}}}
+#{{{ usage
+usage () {
+ cat <<EOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: ./configure [OPTION]...
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [/usr/local]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`/usr/local/bin', \`/usr/local/lib' etc. You can specify
+an installation prefix other than \`/usr/local' using \`--prefix',
+for instance \`--prefix=$HOME'.
+
+For better control, use the options below.
+ --disable-readline Disable line editing support
+ --without-readline Don't use GNU readline even if it is available
+ --without-editline Don't use editline even if it is available
+ --with-readline-includes=DIR Specify where readline include directory is
+ --with-readline-library=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-nettle Don't use nettle even if it is available
+ --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-rtc Don't include RTC even on Linux
+ --disable-privdrop Disable support for dropping root privileges
+ --without-libcap Don't use libcap even if it is available
+ --enable-scfilter Enable support for system call filtering
+ --without-seccomp Don't use seccomp even if it is available
+ --disable-asyncdns Disable asynchronous name resolving
+ --disable-forcednsretry Don't retry on permanent DNS error
+ --without-clock-gettime Don't use clock_gettime() even if it is available
+ --disable-timestamping Disable support for SW/HW timestamping
+ --enable-ntp-signd Enable support for MS-SNTP authentication in Samba
+ --with-ntp-era=SECONDS Specify earliest assumed NTP time in seconds
+ since 1970-01-01 [50*365 days ago]
+ --with-user=USER Specify default chronyd user [root]
+ --with-hwclockfile=PATH Specify default path to hwclock(8) adjtime file
+ --with-pidfile=PATH Specify default pidfile [/var/run/chrony/chronyd.pid]
+ --with-rtcdevice=PATH Specify default path to RTC device [/dev/rtc]
+ --with-sendmail=PATH Path to sendmail binary [/usr/lib/sendmail]
+ --enable-debug Enable debugging support
+
+Fine tuning of the installation directories:
+ --sysconfdir=DIR chrony.conf location [/etc]
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --datarootdir=DIR data root [PREFIX/share]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/chrony]
+ --localstatedir=DIR modifiable single-machine data [/var]
+ --chronyrundir=DIR location for chrony sockets [LOCALSTATEDIR/run/chrony]
+ --chronyvardir=DIR location for chrony data [LOCALSTATEDIR/lib/chrony]
+
+Overriding system detection when cross-compiling:
+ --host-system=OS Specify system name (uname -s)
+ --host-release=REL Specify system release (uname -r)
+ --host-machine=CPU Specify machine (uname -m)
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ CPPFLAGS C preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+
+Use these variables to override the choices made by \`configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+EOF
+
+}
+#}}}
+#{{{
+add_def () {
+ if [ "x$2" = "x" ]; then
+ echo "#define $1 1" >> config.h
+ else
+ echo "#define $1 $2" >> config.h
+ fi
+}
+#}}}
+#{{{ pkg_config
+pkg_config () {
+ type pkg-config > /dev/null 2> /dev/null || return 1
+
+ pkg-config $@ 2> /dev/null
+}
+#}}}
+#{{{ get_features
+get_features () {
+ ff=1
+ for f; do
+ if [ "$ff" = "0" ]; then
+ printf " "
+ fi
+ if grep "define FEAT_$f" config.h > /dev/null; then
+ printf "%s" "+$f"
+ else
+ printf "%s" "-$f"
+ fi
+ ff=0
+ done
+}
+#}}}
+
+# ======================================================================
+
+
+
+OPERATINGSYSTEM=`uname -s`
+VERSION=`uname -r`
+MACHINE=`uname -m`
+
+EXTRA_LIBS=""
+EXTRA_CLI_LIBS=""
+EXTRA_OBJECTS=""
+EXTRA_DEFS=""
+SYSDEFS=""
+
+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_nettle=1
+try_nss=1
+try_tomcrypt=1
+feat_rtc=1
+try_rtc=0
+feat_droproot=1
+try_libcap=-1
+try_clockctl=0
+feat_scfilter=0
+try_seccomp=-1
+priv_ops=""
+readline_lib=""
+readline_inc=""
+ncurses_lib=""
+feat_ipv6=1
+feat_phc=1
+try_phc=0
+feat_pps=1
+try_setsched=0
+try_lockmem=0
+feat_asyncdns=1
+feat_forcednsretry=1
+try_clock_gettime=1
+try_recvmmsg=1
+feat_timestamping=1
+try_timestamping=0
+feat_ntp_signd=0
+ntp_era_split=""
+default_user="root"
+default_hwclockfile=""
+default_pidfile="/var/run/chrony/chronyd.pid"
+default_rtcdevice="/dev/rtc"
+mail_program="/usr/lib/sendmail"
+
+for option
+do
+ case "$option" in
+ --enable-debug )
+ feat_debug=1
+ ;;
+ --disable-readline )
+ feat_readline=0
+ ;;
+ --without-readline )
+ try_readline=0
+ ;;
+ --without-editline )
+ try_editline=0
+ ;;
+ --with-readline-library=* )
+ readline_lib=-L`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --with-readline-includes=* )
+ readline_inc=-I`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --with-ncurses-library=* )
+ ncurses_lib=-L`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --prefix=* | --install_prefix=* )
+ SETPREFIX=`echo $option | sed -e 's/[^=]*=//;'`
+ ;;
+ --exec-prefix=* )
+ SETEPREFIX=`echo $option | sed -e 's/[^=]*=//;'`
+ ;;
+ --sysconfdir=* )
+ SETSYSCONFDIR=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --bindir=* )
+ SETBINDIR=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --sbindir=* )
+ SETSBINDIR=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --datarootdir=* )
+ SETDATAROOTDIR=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --mandir=* )
+ SETMANDIR=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --docdir=* )
+ SETDOCDIR=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --localstatedir=* )
+ SETLOCALSTATEDIR=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --chronyrundir=* | --chronysockdir=* )
+ SETCHRONYRUNDIR=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --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
+ ;;
+ --disable-ipv6)
+ feat_ipv6=0
+ ;;
+ --disable-phc)
+ feat_phc=0
+ ;;
+ --disable-pps)
+ feat_pps=0
+ ;;
+ --disable-privdrop)
+ feat_droproot=0
+ ;;
+ --without-libcap|--disable-linuxcaps)
+ try_libcap=0
+ ;;
+ --enable-scfilter)
+ feat_scfilter=1
+ ;;
+ --disable-scfilter)
+ feat_scfilter=0
+ ;;
+ --without-seccomp)
+ try_seccomp=0
+ ;;
+ --disable-asyncdns)
+ feat_asyncdns=0
+ ;;
+ --disable-forcednsretry)
+ feat_forcednsretry=0
+ ;;
+ --without-clock-gettime)
+ try_clock_gettime=0
+ ;;
+ --disable-timestamping)
+ feat_timestamping=0
+ ;;
+ --enable-ntp-signd)
+ feat_ntp_signd=1
+ ;;
+ --with-ntp-era=* )
+ ntp_era_split=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --with-user=* )
+ default_user=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --with-hwclockfile=* )
+ default_hwclockfile=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --with-pidfile=* )
+ default_pidfile=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --with-rtcdevice=* )
+ default_rtcdevice=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --with-sendmail=* )
+ mail_program=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --disable-sechash )
+ feat_sechash=0
+ ;;
+ --without-nettle )
+ try_nettle=0
+ ;;
+ --without-nss )
+ try_nss=0
+ ;;
+ --without-tomcrypt )
+ try_tomcrypt=0
+ ;;
+ --host-system=* )
+ OPERATINGSYSTEM=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --host-release=* )
+ VERSION=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --host-machine=* )
+ MACHINE=`echo $option | sed -e 's/^.*=//;'`
+ ;;
+ --help | -h )
+ usage
+ exit 0
+ ;;
+ * )
+ echo "Unrecognized option : " $option
+ esac
+done
+
+rm -f config.h config.log
+
+SYSTEM=${OPERATINGSYSTEM}-${MACHINE}
+
+case $OPERATINGSYSTEM in
+ Linux)
+ EXTRA_OBJECTS="sys_generic.o sys_linux.o sys_timex.o"
+ [ $try_libcap != "0" ] && try_libcap=1
+ try_rtc=1
+ [ $try_seccomp != "0" ] && try_seccomp=1
+ try_timestamping=1
+ try_setsched=1
+ try_lockmem=1
+ try_phc=1
+ add_def LINUX
+ echo "Configuring for " $SYSTEM
+ ;;
+ FreeBSD)
+ # recvmmsg() seems to be broken on FreeBSD 11.0 and it's just
+ # a wrapper around recvmsg()
+ try_recvmmsg=0
+ EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
+ add_def FREEBSD
+ if [ $feat_droproot = "1" ]; then
+ add_def FEAT_PRIVDROP
+ priv_ops="ADJUSTTIME ADJUSTTIMEX SETTIME BINDSOCKET"
+ fi
+ echo "Configuring for $SYSTEM"
+ ;;
+ NetBSD)
+ EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
+ try_clockctl=1
+ add_def NETBSD
+ echo "Configuring for $SYSTEM"
+ ;;
+ Darwin)
+ EXTRA_OBJECTS="sys_macosx.o"
+ EXTRA_LIBS="-lresolv"
+ EXTRA_CLI_LIBS="-lresolv"
+ add_def MACOSX
+ if [ $feat_droproot = "1" ]; then
+ add_def FEAT_PRIVDROP
+ priv_ops="ADJUSTTIME SETTIME BINDSOCKET"
+ fi
+ major=`echo $VERSION | cut -d. -f1`
+ # ntp_adjtime is not available in macOS 10.12 (Darwin 16.x.x) and earlier
+ if [ $major -gt "16" ]; then
+ add_def HAVE_MACOS_SYS_TIMEX
+ EXTRA_OBJECTS="$EXTRA_OBJECTS sys_generic.o sys_netbsd.o sys_timex.o"
+ if [ $feat_droproot = "1" ]; then
+ priv_ops="$priv_ops ADJUSTTIMEX"
+ fi
+ fi
+ echo "Configuring for macOS (" $SYSTEM "macOS version" $VERSION ")"
+ ;;
+ SunOS)
+ EXTRA_OBJECTS="sys_generic.o sys_solaris.o sys_timex.o"
+ EXTRA_LIBS="-lsocket -lnsl -lresolv"
+ EXTRA_CLI_LIBS="-lsocket -lnsl -lresolv"
+ add_def SOLARIS
+ # These are needed to have msg_control in struct msghdr
+ add_def __EXTENSIONS__
+ add_def _XOPEN_SOURCE 1
+ add_def _XOPEN_SOURCE_EXTENDED 1
+ if [ $feat_droproot = "1" ]; then
+ add_def FEAT_PRIVDROP
+ priv_ops="ADJUSTTIMEX SETTIME BINDSOCKET"
+ fi
+ echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
+ ;;
+ * )
+ echo "error: $SYSTEM is not supported (yet?)"
+ exit 1
+ ;;
+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"
+ if [ $feat_ntp_signd = "1" ]; then
+ add_def FEAT_SIGND
+ EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_signd.o"
+ fi
+else
+ feat_asyncdns=0
+ feat_timestamping=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
+
+MYCC="$CC"
+MYCFLAGS="$CFLAGS"
+MYCPPFLAGS="$CPPFLAGS"
+MYLDFLAGS="$LDFLAGS"
+
+if [ "x$MYCC" = "x" ]; then
+ for cc in gcc clang cc ""; do
+ if [ "x$cc" = "x" ]; then
+ echo "error: no C compiler found"
+ exit 1
+ fi
+ MYCC=$cc
+ if test_code "$MYCC" '' '' '' ''; then
+ break
+ fi
+ done
+else
+ if ! test_code "$MYCC" '' '' '' ''; then
+ echo "error: C compiler $MYCC cannot create executables"
+ exit 1
+ fi
+fi
+
+if [ "x$MYCFLAGS" = "x" ]; then
+ MYCFLAGS="-O2 -g"
+
+ TESTCFLAGS="-D_FORTIFY_SOURCE=2 -fPIE"
+ TESTLDFLAGS="-pie -Wl,-z,relro,-z,now"
+ if test_code 'hardening compiler options' '' "$TESTCFLAGS" "$TESTLDFLAGS" ''; then
+ MYCFLAGS="$MYCFLAGS $TESTCFLAGS"
+ MYLDFLAGS="$MYLDFLAGS $TESTLDFLAGS"
+ fi
+ TESTCFLAGS="-fstack-protector-strong --param=ssp-buffer-size=4"
+ if test_code '-fstack-protector-strong' '' "$TESTCFLAGS" '' ''; then
+ MYCFLAGS="$MYCFLAGS $TESTCFLAGS"
+ else
+ TESTCFLAGS="-fstack-protector --param=ssp-buffer-size=4"
+ if test_code '-fstack-protector' '' "$TESTCFLAGS" '' ''; then
+ MYCFLAGS="$MYCFLAGS $TESTCFLAGS"
+ fi
+ fi
+fi
+
+if [ "x$MYCC" = "xgcc" ] || [ "x$MYCC" = "xclang" ]; then
+ MYCFLAGS="$MYCFLAGS -Wmissing-prototypes -Wall"
+fi
+
+if test_code '64-bit time_t' 'time.h' '' '' '
+ char x[sizeof(time_t) > 4 ? 1 : -1] = {0};
+ return x[0];'
+then
+ add_def HAVE_LONG_TIME_T 1
+
+ if [ "x$ntp_era_split" != "x" ]; then
+ split_seconds=$ntp_era_split
+ split_days=0
+ else
+ if [ "x$SOURCE_DATE_EPOCH" != "x" ]; then
+ split_seconds=$SOURCE_DATE_EPOCH
+ else
+ split_seconds=`date '+%s'`
+ fi
+ if [ "x$split_seconds" = "x" ]; then
+ echo "error: could not get current time, --with-ntp-era option is needed"
+ exit 1
+ fi
+ split_days=$((50 * 365))
+ fi
+
+ add_def NTP_ERA_SPLIT "(${split_seconds}LL - $split_days * 24 * 3600)"
+
+ date_format='+%Y-%m-%dT%H:%M:%SZ'
+
+ # Print the full NTP interval if a suitable date is found
+ if [ "x`date -u -d '1970-01-01 UTC 9 days ago 5 seconds 3 seconds' \
+ $date_format 2> /dev/null`" = "x1969-12-23T00:00:08Z" ]
+ then
+ time1="`date -u -d "1970-01-01 UTC $split_days days ago $split_seconds seconds" \
+ $date_format`"
+ time2="`date -u -d "1970-01-01 UTC $split_days days ago $split_seconds seconds 4294967296 seconds" \
+ $date_format`"
+ echo "NTP time mapped to $time1/$time2"
+ fi
+fi
+
+MATHCODE='return (int) pow(2.0, log(sqrt((double)argc)));'
+if test_code 'math' 'math.h' '' '' "$MATHCODE"; then
+ LIBS=""
+else
+ if test_code 'math in -lm' 'math.h' '' '-lm' "$MATHCODE"; then
+ LIBS="-lm"
+ else
+ echo "error: could not compile/link a program which uses sqrt(), log(), pow()"
+ exit 1
+ fi
+fi
+
+if test_code 'struct in_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
+ struct in_pktinfo ipi;
+ return sizeof (ipi.ipi_spec_dst.s_addr) + IP_PKTINFO;'
+then
+ add_def HAVE_IN_PKTINFO
+fi
+
+if [ $feat_ipv6 = "1" ] && \
+ test_code 'IPv6 support' 'arpa/inet.h sys/socket.h netinet/in.h' '' "$EXTRA_LIBS" '
+ struct sockaddr_in6 n;
+ char p[100];
+ n.sin6_addr = in6addr_any;
+ return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));'
+then
+ add_def FEAT_IPV6
+ if test_code 'struct in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
+ return sizeof (struct in6_pktinfo) + IPV6_PKTINFO;'
+ then
+ add_def HAVE_IN6_PKTINFO
+ else
+ if test_code 'struct in6_pktinfo with _GNU_SOURCE' 'sys/socket.h netinet/in.h' \
+ '-D_GNU_SOURCE' '' 'return sizeof (struct in6_pktinfo) + IPV6_PKTINFO;'
+ then
+ add_def _GNU_SOURCE
+ add_def HAVE_IN6_PKTINFO
+ fi
+ fi
+fi
+
+if [ $try_clock_gettime = "1" ]; then
+ if test_code 'clock_gettime()' 'time.h' '' '' \
+ 'clock_gettime(CLOCK_REALTIME, NULL);'
+ then
+ add_def HAVE_CLOCK_GETTIME
+ else
+ if test_code 'clock_gettime() in -lrt' 'time.h' '' '-lrt' \
+ 'clock_gettime(CLOCK_REALTIME, NULL);'
+ then
+ add_def HAVE_CLOCK_GETTIME
+ EXTRA_LIBS="$EXTRA_LIBS -lrt"
+ fi
+ fi
+fi
+
+if test_code 'getaddrinfo()' 'sys/types.h sys/socket.h netdb.h' '' "$EXTRA_LIBS" \
+ 'return getaddrinfo(0, 0, 0, 0);'
+then
+ add_def HAVE_GETADDRINFO
+fi
+
+if [ $feat_asyncdns = "1" ] && \
+ test_code 'pthread' 'pthread.h' '-pthread' '' \
+ 'return (int)pthread_create((void *)1, NULL, (void *)1, NULL);'
+then
+ add_def FEAT_ASYNCDNS
+ add_def USE_PTHREAD_ASYNCDNS
+ EXTRA_OBJECTS="$EXTRA_OBJECTS nameserv_async.o"
+ MYCFLAGS="$MYCFLAGS -pthread"
+fi
+
+if test_code 'arc4random_buf()' 'stdlib.h' '' '' 'arc4random_buf(NULL, 0);'; then
+ add_def HAVE_ARC4RANDOM
+fi
+
+if test_code 'getrandom()' 'stdlib.h sys/random.h' '' '' \
+ 'return getrandom(NULL, 256, 0);'; then
+ add_def HAVE_GETRANDOM
+fi
+
+RECVMMSG_CODE='
+ struct mmsghdr hdr;
+ return !recvmmsg(0, &hdr, 1, MSG_DONTWAIT, 0);'
+if [ $try_recvmmsg = "1" ]; then
+ if test_code 'recvmmsg()' 'sys/socket.h' '' "$EXTRA_LIBS" "$RECVMMSG_CODE"; then
+ add_def HAVE_RECVMMSG
+ else
+ if test_code 'recvmmsg() with _GNU_SOURCE' 'sys/socket.h' '-D_GNU_SOURCE' \
+ "$EXTRA_LIBS" "$RECVMMSG_CODE"
+ then
+ add_def _GNU_SOURCE
+ add_def HAVE_RECVMMSG
+ fi
+ fi
+fi
+
+if [ $feat_timestamping = "1" ] && [ $try_timestamping = "1" ] &&
+ test_code 'SW/HW timestamping' 'sys/types.h sys/socket.h linux/net_tstamp.h
+ linux/errqueue.h linux/ptp_clock.h' '' '' '
+ int val = SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_OPT_CMSG;
+ return sizeof (struct scm_timestamping) + SCM_TSTAMP_SND + PTP_SYS_OFFSET +
+ setsockopt(0, SOL_SOCKET, SO_SELECT_ERR_QUEUE + SO_TIMESTAMPING,
+ &val, sizeof (val));'
+then
+ add_def HAVE_LINUX_TIMESTAMPING
+ EXTRA_OBJECTS="$EXTRA_OBJECTS hwclock.o ntp_io_linux.o"
+
+ if test_code 'other timestamping options' \
+ 'sys/types.h sys/socket.h linux/net_tstamp.h' '' '' '
+ struct scm_ts_pktinfo pktinfo;
+ pktinfo.if_index = pktinfo.pkt_length = 0;
+ return pktinfo.if_index + pktinfo.pkt_length + HWTSTAMP_FILTER_NTP_ALL +
+ SCM_TIMESTAMPING_PKTINFO +
+ SOF_TIMESTAMPING_OPT_PKTINFO + SOF_TIMESTAMPING_OPT_TX_SWHW;'; then
+ add_def HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP 1
+ add_def HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO 1
+ add_def HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW 1
+ fi
+fi
+
+timepps_h=""
+if [ $feat_refclock = "1" ] && [ $feat_pps = "1" ]; then
+ if test_code '<sys/timepps.h>' 'inttypes.h time.h sys/timepps.h' '' '' ''; then
+ timepps_h="sys/timepps.h"
+ add_def HAVE_SYS_TIMEPPS_H
+ else
+ if test_code '<timepps.h>' 'inttypes.h time.h timepps.h' '' '' ''; then
+ timepps_h="timepps.h"
+ add_def HAVE_TIMEPPS_H
+ fi
+ fi
+fi
+
+if [ "x$timepps_h" != "x" ] && \
+ test_code 'PPSAPI' "inttypes.h string.h time.h $timepps_h" '' '' '
+ pps_handle_t h = 0;
+ pps_info_t i;
+ struct timespec ts;
+ return time_pps_fetch(h, PPS_TSFMT_TSPEC, &i, &ts);'
+then
+ add_def FEAT_PPS
+fi
+
+if [ $feat_droproot = "1" ] && [ $try_libcap = "1" ] && \
+ test_code \
+ 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_PRIVDROP
+ EXTRA_LIBS="$EXTRA_LIBS -lcap"
+fi
+
+if [ $feat_droproot = "1" ] && [ $try_clockctl = "1" ] && \
+ test_code '<sys/clockctl.h>' 'sys/clockctl.h' '' '' ''
+then
+ add_def FEAT_PRIVDROP
+ priv_ops="BINDSOCKET"
+fi
+
+if [ $feat_scfilter = "1" ] && [ $try_seccomp = "1" ] && \
+ test_code seccomp 'seccomp.h' '' '-lseccomp' \
+ 'seccomp_init(SCMP_ACT_KILL);'
+then
+ add_def FEAT_SCFILTER
+ # NAME2IPADDRESS shouldn't be enabled with other operations as the helper
+ # process works on one request at the time and the async resolver could
+ # block the main thread
+ priv_ops="NAME2IPADDRESS RELOADDNS"
+ EXTRA_LIBS="$EXTRA_LIBS -lseccomp"
+fi
+
+if [ "x$priv_ops" != "x" ]; then
+ EXTRA_OBJECTS="$EXTRA_OBJECTS privops.o"
+ add_def PRIVOPS_HELPER
+ for o in $priv_ops; do
+ add_def PRIVOPS_$o
+ done
+fi
+
+if [ $feat_rtc = "1" ] && [ $try_rtc = "1" ] && \
+ test_code '<linux/rtc.h>' 'sys/ioctl.h linux/rtc.h' '' '' \
+ 'ioctl(1, RTC_UIE_ON&RTC_UIE_OFF&RTC_RD_TIME&RTC_SET_TIME, 0&RTC_UF);'
+then
+ EXTRA_OBJECTS="$EXTRA_OBJECTS rtc_linux.o"
+ add_def FEAT_RTC
+fi
+
+if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
+ grep '#define HAVE_CLOCK_GETTIME' config.h > /dev/null && \
+ test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
+ 'ioctl(1, PTP_CLOCK_GETCAPS + PTP_SYS_OFFSET, 0);'
+then
+ grep 'HAVE_LINUX_TIMESTAMPING' config.h > /dev/null ||
+ EXTRA_OBJECTS="$EXTRA_OBJECTS hwclock.o"
+ add_def FEAT_PHC
+fi
+
+if [ $try_setsched = "1" ] && \
+ test_code \
+ 'sched_setscheduler()' \
+ 'sched.h' '' '' '
+ struct sched_param sched;
+ sched_get_priority_max(SCHED_FIFO);
+ sched_setscheduler(0, SCHED_FIFO, &sched);'
+then
+ add_def HAVE_SCHED_SETSCHEDULER
+fi
+
+if [ $try_lockmem = "1" ] && \
+ test_code \
+ 'mlockall()' \
+ 'sys/mman.h sys/resource.h' '' '' '
+ struct rlimit rlim;
+ setrlimit(RLIMIT_MEMLOCK, &rlim);
+ mlockall(MCL_CURRENT|MCL_FUTURE);'
+then
+ add_def HAVE_MLOCKALL
+fi
+
+if [ $feat_forcednsretry = "1" ]
+then
+ add_def FORCE_DNSRETRY
+fi
+
+READLINE_LINK=""
+if [ $feat_readline = "1" ]; then
+ if [ $try_editline = "1" ]; then
+ if test_code editline 'stdio.h editline/readline.h' \
+ "$readline_inc" "$readline_lib -ledit" \
+ 'add_history(readline("prompt"));'
+ then
+ add_def FEAT_READLINE
+ add_def USE_EDITLINE
+ MYCPPFLAGS="$MYCPPFLAGS $readline_inc"
+ READLINE_LINK="$readline_lib -ledit"
+ fi
+ fi
+
+ if [ "x$READLINE_LINK" = "x" ] && [ $try_readline = "1" ]; then
+ if test_code readline 'stdio.h readline/readline.h readline/history.h' \
+ "$readline_inc" "$readline_lib -lreadline" \
+ 'add_history(readline("prompt"));'
+ then
+ add_def FEAT_READLINE
+ MYCPPFLAGS="$MYCPPFLAGS $readline_inc"
+ READLINE_LINK="$readline_lib -lreadline"
+ fi
+ fi
+
+ if [ "x$READLINE_LINK" = "x" ] && [ $try_readline = "1" ]; then
+ if test_code 'readline with -lncurses' \
+ 'stdio.h readline/readline.h readline/history.h' \
+ "$readline_inc" "$readline_lib $ncurses_lib -lreadline -lncurses" \
+ 'add_history(readline("prompt"));'
+ then
+ add_def FEAT_READLINE
+ MYCPPFLAGS="$MYCPPFLAGS $readline_inc"
+ READLINE_LINK="$readline_lib $ncurses_lib -lreadline -lncurses"
+ fi
+ fi
+
+ EXTRA_CLI_LIBS="$EXTRA_CLI_LIBS $READLINE_LINK"
+fi
+
+HASH_OBJ="hash_intmd5.o"
+HASH_LINK=""
+
+if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nettle = "1" ]; then
+ test_cflags="`pkg_config --cflags nettle`"
+ test_link="`pkg_config --libs nettle`"
+ if test_code 'nettle' 'nettle/nettle-meta.h nettle/sha2.h' \
+ "$test_cflags" "$test_link" \
+ 'return nettle_hashes[0]->context_size;'
+ then
+ HASH_OBJ="hash_nettle.o"
+ HASH_LINK="$test_link"
+ LIBS="$LIBS $HASH_LINK"
+ MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
+ add_def FEAT_SECHASH
+ fi
+fi
+
+if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nss = "1" ]; then
+ test_cflags="`pkg_config --cflags nss`"
+ test_link="`pkg_config --libs-only-L nss` -lfreebl3"
+ if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
+ "$test_cflags" "$test_link" \
+ 'NSSLOWHASH_Begin(NSSLOWHASH_NewContext(NSSLOW_Init(), HASH_AlgSHA512));'
+ then
+ HASH_OBJ="hash_nss.o"
+ HASH_LINK="$test_link"
+ LIBS="$LIBS $HASH_LINK"
+ MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
+ add_def FEAT_SECHASH
+ fi
+fi
+
+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
+ HASH_OBJ="hash_tomcrypt.o"
+ HASH_LINK="-ltomcrypt"
+ LIBS="$LIBS $HASH_LINK"
+ MYCPPFLAGS="$MYCPPFLAGS -I/usr/include/tomcrypt"
+ add_def FEAT_SECHASH
+ fi
+fi
+
+SYSCONFDIR=/etc
+if [ "x$SETSYSCONFDIR" != "x" ]; then
+ SYSCONFDIR=$SETSYSCONFDIR
+fi
+
+PREFIX=/usr/local
+if [ "x$SETPREFIX" != "x" ]; then
+ PREFIX=$SETPREFIX
+fi
+
+EPREFIX=${PREFIX}
+if [ "x$SETEPREFIX" != "x" ]; then
+ EPREFIX=$SETEPREFIX
+fi
+
+BINDIR=${EPREFIX}/bin
+if [ "x$SETBINDIR" != "x" ]; then
+ BINDIR=$SETBINDIR
+fi
+
+SBINDIR=${EPREFIX}/sbin
+if [ "x$SETSBINDIR" != "x" ]; then
+ SBINDIR=$SETSBINDIR
+fi
+
+DATAROOTDIR=${PREFIX}/share
+if [ "x$SETDATAROOTDIR" != "x" ]; then
+ DATAROOTDIR=$SETDATAROOTDIR
+fi
+
+MANDIR=${DATAROOTDIR}/man
+if [ "x$SETMANDIR" != "x" ]; then
+ MANDIR=$SETMANDIR
+fi
+
+DOCDIR=${DATAROOTDIR}/doc/chrony
+if [ "x$SETDOCDIR" != "x" ]; then
+ DOCDIR=$SETDOCDIR
+fi
+
+LOCALSTATEDIR=/var
+if [ "x$SETLOCALSTATEDIR" != "x" ]; then
+ LOCALSTATEDIR=$SETLOCALSTATEDIR
+fi
+
+CHRONYRUNDIR=${LOCALSTATEDIR}/run/chrony
+if [ "x$SETCHRONYRUNDIR" != "x" ]; then
+ CHRONYRUNDIR=$SETCHRONYRUNDIR
+fi
+
+CHRONYVARDIR=${LOCALSTATEDIR}/lib/chrony
+if [ "x$SETCHRONYVARDIR" != "x" ]; then
+ CHRONYVARDIR=$SETCHRONYVARDIR
+fi
+
+add_def DEFAULT_CONF_FILE "\"$SYSCONFDIR/chrony.conf\""
+add_def DEFAULT_HWCLOCK_FILE "\"$default_hwclockfile\""
+add_def DEFAULT_PID_FILE "\"$default_pidfile\""
+add_def DEFAULT_RTC_DEVICE "\"$default_rtcdevice\""
+add_def DEFAULT_USER "\"$default_user\""
+add_def DEFAULT_COMMAND_SOCKET "\"$CHRONYRUNDIR/chronyd.sock\""
+add_def MAIL_PROGRAM "\"$mail_program\""
+
+common_features="`get_features SECHASH IPV6 DEBUG`"
+chronyc_features="`get_features READLINE`"
+chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP SCFILTER SIGND ASYNCDNS`"
+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
+ CHRONY_VERSION="`cat version.txt`"
+else
+ CHRONY_VERSION="DEVELOPMENT"
+fi
+
+add_def CHRONY_VERSION "\"${CHRONY_VERSION}\""
+
+for f in Makefile doc/Makefile test/unit/Makefile
+do
+ echo Creating $f
+ sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
+ s%@CC@%${MYCC}%;\
+ s%@CFLAGS@%${MYCFLAGS}%;\
+ s%@CPPFLAGS@%${MYCPPFLAGS}%;\
+ s%@LIBS@%${LIBS}%;\
+ s%@LDFLAGS@%${MYLDFLAGS}%;\
+ s%@EXTRA_LIBS@%${EXTRA_LIBS}%;\
+ s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\
+ s%@HASH_OBJ@%${HASH_OBJ}%;\
+ s%@SYSCONFDIR@%${SYSCONFDIR}%;\
+ s%@BINDIR@%${BINDIR}%;\
+ s%@SBINDIR@%${SBINDIR}%;\
+ s%@DOCDIR@%${DOCDIR}%;\
+ s%@MANDIR@%${MANDIR}%;\
+ s%@LOCALSTATEDIR@%${LOCALSTATEDIR}%;\
+ s%@CHRONYRUNDIR@%${CHRONYRUNDIR}%;\
+ s%@CHRONYVARDIR@%${CHRONYVARDIR}%;\
+ s%@DEFAULT_HWCLOCK_FILE@%${default_hwclockfile}%;\
+ s%@DEFAULT_PID_FILE@%${default_pidfile}%;\
+ s%@DEFAULT_RTC_DEVICE@%${default_rtcdevice}%;\
+ s%@DEFAULT_USER@%${default_user}%;\
+ s%@CHRONY_VERSION@%${CHRONY_VERSION}%;" \
+ < ${f}.in > $f
+done
+
+# =======================================================================
+# vim:et:sw=2:ht=2:sts=2:fdm=marker:cms=#%s
+
diff --git a/contrib/andrew_bishop_1 b/contrib/andrew_bishop_1
new file mode 100644
index 0000000..4c0b437
--- /dev/null
+++ b/contrib/andrew_bishop_1
@@ -0,0 +1,114 @@
+From amb@gedanken.demon.co.uk Tue Aug 17 22:14:00 1999
+Date: Fri, 6 Aug 1999 19:00:24 +0100
+From: Andrew M. Bishop <amb@gedanken.demon.co.uk>
+To: richard@rrbcurnow.freeserve.co.uk
+Subject: Re: Chrony and laptop configuration
+
+Hi,
+
+Attached is the apmd_proxy script from the apmd-3.0beta9 distribution.
+
+The changes that I would make are the following:
+
+Replace the update_clock function (line 122) with
+
+update_clock () {
+
+chronyd -f /etc/chrony.conf
+
+}
+
+Around line 171 (in the suspend actions section) I would kill chronyd.
+
+begin 644 apmd_proxy.gz
+M'XL("+L@JS<``V%P;61?<')O>'D`I5K[;]M&$OY9^BLV2JZQ6TF.`Q2XUDA1
+MQU8<]>('_&A[.!R,-;D2MR&Y+)?TXZ[WO]\W,\N'%-E)[X08CJ2=V7G/-T,_
+M?[9S8_,=GPR?*_S3119?%Z6[?U`3A=_+4F<JMK[059284BU<J?;/CE6L3>9R
+M$!R4VB[5L2X_WNDRKM161!]D/Z:)T9FVZ73I%]$TUUY/E^YV6[W>Q>$'M?O=
+M=]^!^E#?VEB]+=U=;M)4;<4W/Q;.5]-$E[=@-S5QO:V^4S_5N0DD(+I,K%<^
+M(0(?E;:H%-Y'.DU-K&X>5)68GHAJBU3:5G>)R?DK7^G*@(M;*)T_J,+=0:U,
+MYWII,I-7:E'G465!F&AP372^-/%4X5*CS+V.*F5N<<R#EZ[`IBKM<@D.Q)ID
+ML/F267=VC$UA\E@11W?'7Z@[8NWRA5W6I8G)[!7>9X5-C:IL9J:LYR^V2BP)
+M3>J*HJS`@Z],IG2<V=SZJM05?.(35Z>Q*NJ*M0(SJ!1[TK-4FA7RL(&-DN;H
+MC5&%*>'/#&:K"XC'EH%".O>6"42,GBJ=G>\@F_*%B>S"1DJ7RSIKK0*-25Q<
+M0.*RN<A0]`W9U$51799LU#F[KJ?@2Z]*XR&,MS<VM16\Z=3OM2G9K>""P(@1
+M:(;4:ASM37EK(Z.V;JU6.Y`TVH',VQRKF<-9FY.:FG0:DT+P!MA6^J-(J`O0
+M%*4E[<54HO@[T,/E69&:<?";1<R1!=2H9Q5?>_:P.&:D?JM]!?/B3L-ZMRYC
+M-1/$-%D0$BP=1,/OAD'F8A-";<6[X)(A9^ZL3X@LN$W!2V;2^2`X.;50J\Y3
+MIV.*Q;BTMZ:$U8D+$EG?<(B25+FI[ESYD60`1QW1W;^T:=**#(?4%",I[%..
+M0T`\8@HYJW(R=SH:4UQ+T%%4@Z_SC8DI-+M(+`T)B9A@P\\7+,)'4Z(J2"ZS
+M%B0-G:/LW)WNOJ(@2.R2ZM)6[<69),T(/$(&D+T6EM*OKK;'_5B.=(YKJ[K,
+M$1#*E"6817``AXT$6^,7XH/DR&-4%\G^,8P6VP@A!5NBM%1)*`%TGCXC5ZYI
+M^)N)*H[Z3^(J2$0^CN%-R&`78W6C81`E1?;LBG1M'$86O*7DP&?0&W;)$2FU
+MV!4L6\$10A6%-=7%$(IDS;?STXM-HK'Q\7KV3)V<7L[HMY)JBW^YJT*VM`+7
+M(B"41<`?FAL+0TK<^&>!U_GL\NK\1/V\_^%J]KUP5Z_06G*'^-9I\,#>$Z96
+ME.TZBDQ1<:FDURXXB-0]9:D*!LJMXZN+2_5^_^<9ZWMX/O]Y=BXA<WJNWL^/
+MWL_.MUG"]X:XEV:E?GN#DI-'QG,L=`I_OUX/<5]9J977I-][J-SQ&2GR?4)7
+MJ"<(N<'5%8=7C.:X1KU2<'K4X0.ZMB0=/+F^7UTV\T'IK1#,Z3J?$..P0WNB
+M(=GZ>OL34[#IOU"F<)ID4IN%XL!N3'-%;[Y8K<#\LQQZ0JQR"&6LN4(X7/05
+MD9*X*%WVA"`-FW#/9]A\3IJ>EYY@L^ZI55:"9U!:JHIZZB=>*DWA*%I5"J@2
+M3FWD(+!)/<%A_V"GN49H-O+AOO`DG]R0:E23Z6A=Q-2F/PF_P"[2A0[`X1%V
+M`KNF#<'6-U('P'`U`ZD8HS;"&^BNTJZYVZ%.H-.T%8)(OV'26X!=-%>JW1LZ
+MEZ\+$@"5%!`Y?(:?Z5H?$V$NYL=G'^;OYK-#=7!Z\FY^='6^?SD_/5$JX%_`
+M'X``!C0$-OL(D=H:Y(::5>D8JAG+W8ERTTA%D>ZVP-?NCMX#:EL2W?>A4/HP
+M)KFH#L>V(6L!=^5-NI"&<6$J=75YP)"JK%G_!U>CF:8N^DB5K&ED<HK@;>@J
+M)`]Q!A.\<[!':>,8``27$HH-\L)HN=HQ5;0#9XK_=ICY=`B.;Q8Z]::5Y.+J
+MXFQV<GA]>G*]SS+QUT&H%D+I6V?C34T'7$+;X8&!%<ET!!QN&/VZ/.=>24S`
+MG],`ZKRESKW0=5IUL,&S+QCMDO*-&T).T!S5T`]7A'Y#5F1]S@Z.#^;[8%,&
+M9AR0`G[A+;@+H)MCCE3*)=Z#3JS%5,`4:9[H6S0ZYB50'/RHI=^T90Y*D?--
+MF:*!^AJ@#;5%JXN#BSGA*1`"0%5D%<1PAQY&`3V,`N15AN`DM]$^K`UQ*[I0
+MPZ7+B^3!4['"C8'+GD)8PTYC05-<96A$`$C@'NH6"PZT!#E-<)\A'S&-JE1X
+MC!KH-V:_,H!EP,0XB`<=\)&:.1V*B:]G/\T.+LG\P1-=4-&0.GM[=70T/SGB
+M=U<Y\:=)L1FR@+9CB!D<?#R[?']Z"(CBVO^_YOH5FYMZN91PS^`]#)P^Z-)4
+MJ=2A,JD36*8T<DL<BM_2Y$CXE'K:&,`?I8>2IN(RU6@GT0J,_U&B!&[.N7RV
+M`ZP'5W((\*H3"`\NN%1196O5(;,)'F[%1*US-?E51NRN\$H):'6>J`]NZ5OP
+MG5+:=,/AZESL\O1!KJ?YN??%BZ^I&W1L7S=LP<1"K[+.UUC!BCM55NSTY`);
+MRN4H<>KEUVNOE^J''YXB&+UX!2%&?73V*`&WHPVOIV]X.5E[/272O8DV7/#Z
+M40*4336Y9\?L4\5");#4K*@0)ZK$)!2J&<(HK6,I9IZ6$_33#MQ->2*.E:[J
+ML`Y8-^;_\!H.A\SY&L+1\&ZVMM6_AP,IX//#&4_Y$LB^``@%``X#I".\GZ"1
+M\GLB.>215L(RE&#(.=CQM-5*XD)C4)[\KB87:O>O:B<VM_A0#P:@Q/LW;]!_
+MOU4816J@W.&`*N_>\#^->&'0UK!=(V&X[A$I_YQ`KUIY>C<_Y]'K>]4-:LT$
+MCR88<,7KZ6M.4I[(I;(CU6/>*J"O#@4D74L#;B0/R"FP@"4S6NEU"Q4^/1R@
+M4?Y#318;^ZWZYQXW@.&``G"Z\8Q\AT*=4D]]2(U\P&Q'+PX^G![\[?CT<#92
+M;]31\67'<4"MG#L?GU_8X8!^F.X%`8<WH9.OR/#NP_[1F]%H.#!4KGL?3>J1
+M,(`R]TJ,'W107WT5L,G$JQ=T7/WQATKN5C\C7Q"DX`D/U2;3L#_MEDQ<EX1@
+MYDWRD/'".,\ESCM$:F9I&Q?2I[==!(>%I2%S')8QJX&",HVX+B<"F:0K]!%%
+M#ZFTB*`9W\G&=S+,HL=UX.+Y<!B!':R_.T(0#8?DGO7Z$UX-?.*++B[W3P[?
+M_OV1L\SF/8>=BFH,M)G]%REC$(_6=9OB9JYAT?O@Q#,'M$RRYJ%I-B<NH"Y1
+M?LS@I;_]"HB'K>P6S*-*6@^T:S#&.`)QIZ3R*-P]^F,4)!IM#RDO]ION*2C:
+M+-E/:W@Q^"HLMMK9:O`)6OS$_"W4%;[4]!0M<9#/"Z)G7;NE#'MYM+Y1;#8A
+M"\IW>-W&*1<_%"CKJ+GOI]X%4\GRD9ID3N;4Z@.JVWUO)"'";@+9N$RC#LN+
+MM)7UV12434:NPNPF-R=:O7B-=P'.=,D-(I=?Z^A:$-T/7/CR.DW;$P-S#SBS
+M2^X\E\W.%N^@@MQA?FK5DRB(MT$92D4CV2[='V*N$X"YOY*2P%G=WS!5#T5`
+MH;%C7+ITJM"^DI`HG,VKL;JI&3,3>0B.!@?"-K(9N\$(PY@'K?)/AU8`^V&9
+M[:5DTU9^)6<"D`N'@QO#,HTBBR#=H+>YY"4M0>X`S@D+)S+,K:EFR@HECHC;
+M>>.)^0!?06J,B#0>"`7'!TGG&YC?.`LW1V91DX#>+2IJ-Y-N'2H#"NO;0FN6
+MCK:Q8>)@*4H!``CUE9.<"9$KY<%!+`L\,;4`\_/9Q=7Q##<=A/U>,S#T+#7B
+M%2=C9:Y<88V)O*:5=3`W!IF:I^22[]3MR$\&)&,ANR::U.M=1B"]1>..8)AE
+MY])Y--\,=NDE5M>LPDP30EA)$B&^'YE8$/4\?7<A/UAEQ`:G3.!.N?YM6]&Z
+M=.J/.AL"&#-)J8O$1EZ&RM@961++:,5YDG=G>-/7Q8\UM$)7OR)B"3DA>$*A
+ME/K-+N4-C6_6#H8>3#@,?655:YI6<N^H(M?9#7R\.PX/&L2XM:\Y'S`@FONJ
+M.8P[KBBE1,)Q2$.D".^8*M?="J@,+(#K6-%?V]O0R9FQ>.RY:GU6^Y*?HT;)
+M;=7YX+D:K'ZSNZ=\:DRA=NG+8&;'<R.9&K*%_@4`*,]PX%57TVZ&^EV`@D0T
+M^W7_^.P#@.+I!=H&AK.8NR0Y(/AR)^P-&Z,3E:Q"`^.D9<A=6)Z+4:R5A@_4
+MG:T"K5)GF,[YHEM=/M#BHTO,T)A'+(S+:1_`S7?P7(P`>*53>=C,)Q;H?WM[
+M3\*1%I9("C]U;"B=@S6>3J>K.U6**^#JLS%@`CU(D&T_XSV!Q5-""*(J8`&5
+ML;8ET%%IH:&K"1V%#(_OC,`P<D'1/N[^?`/H%B<K>Q[N(DTI;8!A;]]G^=9&
+MV"[L>;%M2ZE?7-D^4\+6*E:ON7,+#QT$+?VQFO1_ER1+T]_C-:D)O7Y)>B17
+M0L1^+E?"L2YEPJ'I>F`_&K3YE\<LX//YY9.GF,U!>*!.B<=/5A>V1-ODQT9^
+MRD?F?6#?+!`9287V2!]E%-8(C&:F'C7XG[`O,4-@*_4%2.R3V;>9K@:K0[N`
+MJ2^WQNG9TX<V6X/"W92$;_@))9TY##F1,3Y8.8JB,@X9<D//_=6HI\<H;"+9
+M(*Z@1-^@Z]Z>>EHC=?!^_^1H1MSAXLNKBT=/TDW23^@N'L*06S;,KB.^G+ZA
+M9+VS]`<VU(5VN'0U`\18Z1B@!,4\0UV(&_>CDE71EP'K#3JV";?N478I^50D
+MI"5+$%`FGU0ZC/P1"#Y?J7@]PB!EH&U"ELIPI4;H"B.5`L^F:DLV'&9!H!EV
+M5&:ZG-+>^=M7?Q%:P-"7%>'RC#;2\D<[%2/8VA.F[-_:/?T)%PLWLA_J]5VW
+>Z]AB9"M2/=L.+(S7D<0S_V\81H;_`M>*^#$A)0``
+`
+end
+
+--
+Andrew.
+----------------------------------------------------------------------
+Andrew M. Bishop amb@gedanken.demon.co.uk
+ http://www.gedanken.demon.co.uk/
+
diff --git a/contrib/andrew_bishop_2 b/contrib/andrew_bishop_2
new file mode 100644
index 0000000..d3ede74
--- /dev/null
+++ b/contrib/andrew_bishop_2
@@ -0,0 +1,95 @@
+From amb@gedanken.demon.co.uk Wed Sep 1 22:26:59 1999
+Date: Thu, 19 Aug 1999 17:30:14 +0100
+From: Andrew M. Bishop <amb@gedanken.demon.co.uk>
+To: richard@rrbcurnow.freeserve.co.uk
+Subject: [amb@gedanken.demon.co.uk: Chrony and laptop configuration]
+
+Hi,
+
+What you need to do is replace 10.0.0.0 with the network of the
+freeserve nameservers in the two scripts below.
+
+Other than that you can use it as is.
+
+------- Start of forwarded message -------
+From: "Andrew M. Bishop" <amb@gedanken.demon.co.uk>
+To: richard@rrbcurnow.freeserve.co.uk
+Subject: Chrony and laptop configuration
+Date: Sat, 31 Jul 1999 11:02:04 +0100
+
+Attached are the ip-up and ip-down files that I use for chrony.
+(Actually because of the way that debian works they are separate file
+in the /etc/ppp/ip-up.d directory that are run in a SysV init style).
+
+They rely on the presence of an 'ipparam demon' or 'ipparam freeserve'
+line in the PPP options file.
+
+-------------------- /etc/ppp/ip-up --------------------
+#!/bin/sh -f
+#
+# A script to start chrony
+#
+
+PPP_IPPARAM="$6"
+
+if [ $PPP_IPPARAM = "demon" ]; then
+
+ /usr/local/bin/chronyc << EOF
+password xxxxxxx
+online 255.255.255.0/158.152.1.0
+online 255.255.255.0/194.159.253.0
+EOF
+
+fi
+
+if [ $PPP_IPPARAM = "freeserve" ]; then
+
+ /usr/local/bin/chronyc << EOF
+password xxxxxxx
+online 255.255.255.0/10.0.0.0
+EOF
+
+fi
+-------------------- /etc/ppp/ip-up --------------------
+
+-------------------- /etc/ppp/ip-down --------------------
+#!/bin/sh -f
+#
+# A script to stop chrony
+#
+
+PPP_IPPARAM="$6"
+
+if [ $PPP_IPPARAM = "demon" ]; then
+
+ /usr/local/bin/chronyc << EOF
+password xxxxxxx
+offline 255.255.255.0/158.152.1.0
+offline 255.255.255.0/194.159.253.0
+EOF
+
+fi
+
+if [ $PPP_IPPARAM = "freeserve" ]; then
+
+ /usr/local/bin/chronyc << EOF
+password xxxxxxx
+offline 255.255.255.0/10.0.0.0
+EOF
+
+fi
+-------------------- /etc/ppp/ip-down --------------------
+
+--
+Andrew.
+----------------------------------------------------------------------
+Andrew M. Bishop amb@gedanken.demon.co.uk
+ http://www.gedanken.demon.co.uk/
+------- End of forwarded message -------
+
+--
+Andrew.
+----------------------------------------------------------------------
+Andrew M. Bishop amb@gedanken.demon.co.uk
+ http://www.gedanken.demon.co.uk/
+
diff --git a/contrib/bryan_christianson_1/README.txt b/contrib/bryan_christianson_1/README.txt
new file mode 100644
index 0000000..3a0a2ef
--- /dev/null
+++ b/contrib/bryan_christianson_1/README.txt
@@ -0,0 +1,103 @@
+Notes for installing chrony on macOS
+Author: Bryan Christianson (bryan@whatroute.net)
+------------------------------------------------
+
+These files are for those admins/users who would prefer to install chrony
+from the source distribution and are intended as guidelines rather than
+being definitive. They can be edited with a plain text editor, such as
+vi, emacs or your favourite IDE (Xcode)
+
+It is assumed you are comfortable with installing software from the
+terminal command line and know how to use sudo to acquire root access.
+
+If you are not familiar with the macOS command line then
+please consider using ChronyControl from http://whatroute.net/chronycontrol.html
+
+ChronyControl provides a gui wrapper for installing these files and sets the
+necessary permissions on each file.
+
+
+Install the chrony software
+---------------------------
+
+You will need xcode and the commandline additions to build and install chrony.
+These can be obtained from Apple's website via the App Store.
+
+cd to the chrony directory
+./configure
+make
+sudo make install
+
+chrony is now installed in default locations (/usr/local/sbin/chronyd,
+/usr/local/bin/chronyc)
+
+Create a chrony.conf file - see the chrony website for details
+
+The support files here assume the following directives are specified in the
+chrony.conf file
+
+keyfile /etc/chrony.d/chrony.keys
+driftfile /var/db/chrony/chrony.drift
+bindcmdaddress /var/db/chrony/chronyd.sock
+logdir /var/log/chrony
+dumpdir /var/db/chrony
+
+Install this file as /etc/chrony.d/chrony.conf and create
+the directories specified in the above directives if they don't exist.
+You will need root permissions to create the directories.
+
+
+Running chronyd
+---------------
+At this point chronyd *could* be run as a daemon. Apple discourage running
+daemons and their preferred method uses the launchd facility. The
+support files here provide a launchd configuration file for chronyd and also
+a shell script and launchd configuration file to rotate the chronyd logs on a daily basis.
+
+
+Support files
+-------------
+Dates and sizes may differ
+-rw-r--r-- 1 yourname staff 2084 4 Aug 22:54 README.txt
+-rwxr-xr-x 1 yourname staff 676 4 Aug 21:18 chronylogrotate.sh
+-rw-r--r-- 1 yourname staff 543 18 Jul 20:10 org.tuxfamily.chronyc.plist
+-rw-r--r-- 1 yourname staff 511 19 Jun 18:30 org.tuxfamily.chronyd.plist
+
+If you have used chrony support directories other than those suggested, you
+will need to edit each file and make the appropriate changes.
+
+
+Installing the support files
+----------------------------
+
+1. chronylogrotate.sh
+This is a simple shell script that deletes old log files. Unfortunately because
+of the need to run chronyc, the standard macOS logrotation does not work with
+chrony logs.
+
+This script runs on a daily basis under control of launchd and should be
+installed in the /usr/local/bin directory
+
+sudo cp chronylogrotate.sh /usr/local/bin
+sudo chmod +x /usr/local/bin/chronylogrotate.sh
+sudo chown root:wheel /usr/local/bin/chronylogrotate.sh
+
+
+2. org.tuxfamily.chronyc.plist
+This file is the launchd plist that runs logrotation each day. You may
+wish to edit this file to change the time of day at which the rotation
+will run, currently 04:05 am
+
+sudo cp org.tuxfamily.chronyc.plist /Library/LaunchDaemons
+sudo chown root:wheel /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
+sudo chmod 0644 /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
+sudo launchctl load -w /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
+
+
+3. org.tuxfamily.chronyd.plist
+This file is the launchd plist that runs chronyd when the Macintosh starts.
+
+sudo cp org.tuxfamily.chronyd.plist /Library/LaunchDaemons
+sudo chown root:wheel /Library/LaunchDaemons/org.tuxfamily.chronyd.plist
+sudo chmod 0644 /Library/LaunchDaemons/org.tuxfamily.chronyd.plist
+sudo launchctl load -w /Library/LaunchDaemons/org.tuxfamily.chronyd.plist
diff --git a/contrib/bryan_christianson_1/chronylogrotate.sh b/contrib/bryan_christianson_1/chronylogrotate.sh
new file mode 100755
index 0000000..f919544
--- /dev/null
+++ b/contrib/bryan_christianson_1/chronylogrotate.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+# chronyd/chronyc - Programs for keeping computer clocks accurate.
+#
+# **********************************************************************
+# * 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.
+# *
+# **********************************************************************
+
+LOGDIR=/var/log/chrony
+
+rotate () {
+ prefix=$1
+
+ rm -f $prefix.log.10
+
+ for (( count=9; count>= 0; count-- ))
+ do
+ next=$(( $count+1 ))
+ if [ -f $prefix.log.$count ]; then
+ mv $prefix.log.$count $prefix.log.$next
+ fi
+ done
+
+ if [ -f $prefix.log ]; then
+ mv $prefix.log $prefix.log.0
+ fi
+}
+
+if [ ! -e "$LOGDIR" ]; then
+ logger -s "missing directory: $LOGDIR"
+ exit 1
+fi
+
+cd $LOGDIR
+
+rotate measurements
+rotate statistics
+rotate tracking
+
+#
+# signal chronyd via chronyc
+/usr/local/bin/chronyc cyclelogs > /dev/null
+
+exit $? \ No newline at end of file
diff --git a/contrib/bryan_christianson_1/org.tuxfamily.chronyc.plist b/contrib/bryan_christianson_1/org.tuxfamily.chronyc.plist
new file mode 100644
index 0000000..a3c42c6
--- /dev/null
+++ b/contrib/bryan_christianson_1/org.tuxfamily.chronyc.plist
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>org.tuxfamily.logrotate</string>
+ <key>KeepAlive</key>
+ <false/>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/bin/sh</string>
+ <string>/usr/local/bin/chronylogrotate.sh</string>
+ </array>
+ <key>StartCalendarInterval</key>
+ <dict>
+ <key>Minute</key>
+ <integer>5</integer>
+ <key>Hour</key>
+ <integer>4</integer>
+ </dict>
+</dict>
+</plist>
diff --git a/contrib/bryan_christianson_1/org.tuxfamily.chronyd.plist b/contrib/bryan_christianson_1/org.tuxfamily.chronyd.plist
new file mode 100644
index 0000000..2bf42aa
--- /dev/null
+++ b/contrib/bryan_christianson_1/org.tuxfamily.chronyd.plist
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>org.tuxfamily.chronyd</string>
+ <key>Program</key>
+ <string>/usr/local/sbin/chronyd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>chronyd</string>
+ <string>-n</string>
+ <string>-f</string>
+ <string>/private/etc/chrony.d/chrony.conf</string>
+ </array>
+ <key>KeepAlive</key>
+ <true/>
+</dict>
+</plist>
diff --git a/contrib/erik_bryer_1 b/contrib/erik_bryer_1
new file mode 100644
index 0000000..c551dfe
--- /dev/null
+++ b/contrib/erik_bryer_1
@@ -0,0 +1,65 @@
+#!/bin/sh
+#
+# chrony Start time synchronization. This script
+# starts chronyd.
+#
+# Hacked by: Erik Bryer <ebryer@spots.ab.ca> using inet as a template
+#
+# chkconfig: 2345 02 82
+# description: chronyd helps keep the system time accurate by calculating \
+# and applying correction factors to compensate for the drift \
+# in the clock. chronyd can also correct the hardware clock \
+# (RTC) on some systems.
+# processname: chronyd
+# config: /etc/chrony.conf
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+# Source networking configuration.
+. /etc/sysconfig/network
+
+# Set path to include chronyd in /usr/local/sbin
+PATH="$PATH:/usr/local/sbin"
+
+[ -f /usr/local/sbin/chronyd ] || exit 0
+
+[ -f /etc/chrony.conf ] || exit 0
+
+RETVAL=0
+
+# See how we were called.
+case "$1" in
+ start)
+ # Start daemons.
+ echo -n "Starting chronyd: "
+ daemon chronyd
+ RETVAL=$?
+ [ $RETVAL -eq 0 ] && touch /var/lock/subsys/chrony
+ echo
+ ;;
+ stop)
+ # Stop daemons.
+ echo -n "Shutting down chronyd: "
+# If not dead killproc automatically sleeps for 4.1 seconds then does
+# kill -9. "chrony.txt" prefers a 5 second delay, but this should be ok.
+ killproc chronyd -15
+ RETVAL=$?
+ [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/chrony
+ echo
+ ;;
+ status)
+ status chronyd
+ exit $?
+ ;;
+ restart)
+ $0 stop
+ $0 start
+ ;;
+ *)
+ echo "Usage: named {start|stop|status|restart}"
+ exit 1
+esac
+
+exit $RETVAL
+
diff --git a/contrib/ken_gillett_1 b/contrib/ken_gillett_1
new file mode 100644
index 0000000..48b7999
--- /dev/null
+++ b/contrib/ken_gillett_1
@@ -0,0 +1,100 @@
+#!/bin/sh
+#
+# chronyd This shell script takes care of starting and stopping
+# chronyd (NTP daemon).
+#
+# chkconfig: 45 80 20
+# description: chronyd is the NTP daemon.
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+# Source networking configuration.
+. /etc/sysconfig/network
+
+# Check that networking is up.
+[ ${NETWORKING} = "no" ] && exit 0
+
+PREDIR="/usr/local"
+CHRONYD=$PREDIR"/sbin/chronyd"
+CHRONYC=$PREDIR"/bin/chronyc"
+
+[ -x $CHRONYD -a -x $CHRONYC -a -f /etc/chrony.conf ] || exit 0
+
+dochrony() {
+ if [ -z "$(pidofproc chronyd)" ]; then
+ echo -e "\n\tchronyd not running\n\n"
+ exit 2
+ fi
+ KEY=`awk '$1 == "commandkey" {print $2; exit}' /etc/chrony.conf`
+ PASSWORD=`awk '$1 == '$KEY' {print $2; exit}' /etc/chrony/keys`
+
+ $CHRONYC <<- EOF
+ password $PASSWORD
+ $@
+ quit
+ EOF
+}
+
+# make the first parameter' lower case
+set - `echo $1 | awk '{print tolower($1)}';shift;echo "$@"`
+
+# Expand any shortcuts.
+case "$1" in
+ on|1)
+ set - "online"
+ ;;
+ off|0)
+ set - "offline"
+esac
+
+# See how we were called.
+case "$1" in
+ start)
+ # Start daemons.
+ echo -n "Starting chronyd: "
+ daemon $CHRONYD
+ if [ $? -eq 0 ]; then
+ echo $(pidofproc chronyd) > /var/run/chronyd.pid
+ touch /var/lock/subsys/chronyd
+ fi
+ echo
+ ;;
+ stop)
+ # Stop daemons.
+ echo -n "Shutting down chronyd: "
+ killproc chronyd
+ echo
+ rm -f /var/lock/subsys/chronyd
+ ;;
+ status)
+ status chronyd
+ ;;
+ restart|reload)
+ $0 stop
+ $0 start
+ ;;
+ condrestart)
+ if [ -f /var/lock/subsys/chronyd ]; then
+ $0 stop
+ $0 start
+ fi
+ ;;
+ "")
+ echo "Usage: chronyd
+{start|stop|restart|reload|condrestart|status|[on|off]line etc}"
+ exit 1
+ ;;
+
+accheck|cmdaccheck|clients|manual|rtcdata|sources|sourcestats|tracking|clients)
+ dochrony "$@"
+ ;;
+ *)
+ echo -n "Chrony $1: "
+ dochrony "$@" > /dev/null
+ [ $? -eq 0 ] && echo_success || echo_failure
+ echo
+esac
+
+exit 0
+
diff --git a/contrib/stephan_boettcher_1 b/contrib/stephan_boettcher_1
new file mode 100644
index 0000000..e5eda11
--- /dev/null
+++ b/contrib/stephan_boettcher_1
@@ -0,0 +1,162 @@
+From stephan@nevis1.nevis.columbia.edu Mon Jun 7 20:51:57 1999
+Date: 04 Jun 1999 00:17:25 -0400
+From: Stephan I. Boettcher <stephan@nevis1.nevis.columbia.edu>
+To: richard@rrbcurnow.freeserve.co.uk
+Subject: chrony 1.1 sysV startup script for notebooks
+
+
+Dear Richard,
+
+I installed chrony on my notebook, running RedHat 5.1 Linux.
+It looks like it works. No problems.
+
+Thank you!
+
+I like to donate my sysV startup script, appended below.
+
+Special feature: the `online' command scans the config file to
+selectively turn some servers online, depending on the pcmcia SCHEME.
+
+booting: /etc/rc.d/init.d/chrony start
+/etc/ppp/ip-up: /etc/rc.d/init.d/chrony online
+/etc/ppp/ip-down: /etc/rc.d/init.d/chrony offline
+logrotate cron: /etc/rc.d/init.d/chrony cyclelogs
+a user: /etc/rc.d/init.d/chrony status
+a sysadmin: /etc/rc.d/init.d/chrony restart
+shutdown: /etc/rc.d/init.d/chrony stop
+
+Best regards
+Stephan
+
+--
+
+------------------------------------------------------------------------
+Stephan Boettcher FAX: +1-914-591-4540
+Columbia University, Nevis Labs Tel: +1-914-591-2863
+P.O. Box 137, 136 South Broadway mailto:stephan@nevis1.columbia.edu
+Irvington, NY 10533, USA http://www.nevis.columbia.edu/~stephan
+------------------------------------------------------------------------
+
+########################### cut here ###################################
+#! /bin/bash
+#
+# /etc/rc.d/init.d/chrony
+#
+# SYS V startup script for
+# chrony ntp daemon
+# on Linux 2.0.3x notebooks with pcmcia scheme support
+# $Id: stephan_boettcher_1,v 1.1 2000/04/24 21:36:04 richard Exp $
+#
+# 1999-06-02 SiB <stephan@nevis1.columbia.edu>
+#
+# For PCMCIA users:
+# In /etc/chrony.conf, precede the server commands for each SCHEME
+# with a comment line that contains the word SCHEME and the name of
+# the scheme(s) that should use the servers, up to the next line that
+# contains the word SCHEME. The servers must be `offline' and
+# specified by their IP address. The hostname will not do.
+#
+# Like:
+#
+# # SCHEME nevisppp nevislan
+# # stephanpc.nevis.columbia.edu
+# server 192.12.82.222 offline
+#
+# # SCHEME desyppp desylan
+#
+# # dsygw2.desy.de
+# server 131.169.30.15 offline
+# # dscomsa.desy.de
+# server 131.169.197.35 offline
+
+CONF=/etc/chrony.conf
+CHRONYD=/usr/local/sbin/chronyd
+CHRONYC=/usr/local/bin/chronyc
+KEYS=/etc/chrony.keys
+
+# See if we got all we need:
+
+[ -f $CHRONYD -a -f $CHRONYC -a -r $CONF ] || exit
+
+
+[ -r $KEYS ] \
+&& CMDKEY=`awk '/^commandkey/{print $2}' $CONF` \
+&& PASSWORD=`awk -v KEY=$CMDKEY '$1==KEY{print $2}' $KEYS`
+
+
+case "$1" in
+
+ start)
+ echo -n "Starting chronyd "
+ $CHRONYD -r -s -f $CONF
+ echo
+ ;;
+
+ stop)
+ echo -n "Shutting down chronyd "
+ /usr/bin/killall chronyd
+ echo
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ;;
+
+ on*)
+
+ [ -f /var/run/pcmcia-scheme ] && SCHEME=`cat /var/run/pcmcia-scheme`
+
+ awk -v SCHEME=${SCHEME:-default} -v PASSWORD=$PASSWORD \
+ '
+ BEGIN {
+ SEL=1;
+ print "password", PASSWORD;
+ }
+ /SCHEME/ {
+ SEL=match($0, SCHEME);
+ }
+ SEL && /^server[ \t]*[0-9.]+[ \t].*offline/ {
+ print "online 255.255.255.255/" $2;
+ }
+ ' \
+ $CONF \
+ | $CHRONYC
+
+ ;;
+
+ off*)
+ cat <<-EOF | $CHRONYC
+ password $PASSWORD
+ offline
+ trimrtc
+ dump
+ EOF
+ ;;
+
+ *log*)
+ cat <<-EOF | $CHRONYC
+ password $PASSWORD
+ cyclelogs
+ EOF
+ ;;
+
+ stat*)
+ cat <<-EOF | $CHRONYC
+ sources
+ sourcestats
+ tracking
+ rtcdata
+ EOF
+ ;;
+
+ *)
+ echo "Usage: chronyd {start|stop|restart|status|online|offline|cyclelogs}"
+ exit 1
+ ;;
+
+esac
+
+exit 0
+
+
diff --git a/contrib/wolfgang_weisselberg1 b/contrib/wolfgang_weisselberg1
new file mode 100644
index 0000000..2c41752
--- /dev/null
+++ b/contrib/wolfgang_weisselberg1
@@ -0,0 +1,118 @@
+
+> Is it possible to limit chronyc to only those commands that
+> are readonly plus those necessary to bring a dialup connection up
+> and down? That is: online offline dump writertc and password.
+
+This is trivial on the same host and workable for non-local
+hosts: use a wrapper program or script. An *untested*
+sample follows. To use it, best create a special user (say
+chronyc) and a special group (say chronyg). Make the script
+chronyc:chronyg, and 4750 (suid, rwxr-x---). Add all users
+who may run the script to the group chronyg.
+
+Make a chrony password file e.g.
+/usr/local/etc/chrony_password. It should be owned by chronyc
+and readable only for the owner, containing only the chrony
+password (and maybe a newline) in the first line.
+
+In this way only the script (call it run_chrony, for example)
+can read the password. It will allow only those commands you
+explicitely allow. You can add a password check -- especially
+if you add an internet port so you can access it over the
+internet this is advisable. You really want to add logging
+to this untested script as well.
+
+
+BTW, if you use some sort of PPP, you probably can use
+/etc/ppp/ip-up and /etc/ppp/ip-down to transparently set chrony
+on- and offline as the ip connection goes up and comes down.
+This is _far_ more user friendly, IMHO, and a DOS by switching
+chrony offline all the time is avoided as well.
+
+
+#! /usr/bin/perl -T
+use v5.6.1;
+use warnings;
+use strict;
+
+sub laundered_command();
+sub order_chrony($$);
+sub read_password();
+sub usage($);
+
+our $CHRONY = "/usr/local/bin/chronyc";
+
+# NOTE: select the file system protection wisely for the
+# PASSWORDFILE!
+our $PASSWORDFILE = "/usr/local/etc/chrony_password";
+
+our @ALLOWED_COMMANDS = (
+ 'online', # switch online mode on
+ 'offline', # switch online mode off
+ 'dump', # save measurements to file
+ 'writerc', # save RTC accumulated data
+
+ 'clients', # which clients are served by us?
+ 'rtcdata', # Quality of RTC measurements
+ 'sources(?: -v)?', # Show our sources (verbose)
+ 'sourcestats(?: -v)?', # How good are our sources (verbose)?
+ 'tracking', # whom do we adjust to?
+
+ # 'burst \d+/\d+', # allow them to send bursts?
+);
+
+usage("No command given.") unless $ARGV[0];
+
+%ENV = (); # nuke all environment variables. Rather
+ # drastic, but better safe than sorry!
+ # Add whatever you really need to get it
+ # working (again).
+$ENV{'PATH'} = '/usr/local/bin:/bin:/usr/bin';
+
+order_chrony(laundered_command(), read_password());
+
+exit 0; # command succeeded
+
+############################################################
+
+sub usage($) {
+ print STDERR "Error: ", shift, "\n";
+
+ # OK, this eats the -v...
+ print STDERR "Legal commands are:\n\t", join "\n",
+ map { $_ =~ m:(\w+):; $1 } @ALLOWED_COMMANDS;
+ exit 1; # error
+}
+
+############################################################
+
+sub laundered_command() {
+ my $regexp = "^(" . join ( "|", @ALLOWED_COMMANDS ) . ")\$";
+ my $parameters = join " ", @ARGV;
+ $parameters =~ m:$regexp: or usage("Command $parameters not allowed.");
+
+ return $1; # this value, then, is untainted.
+};
+
+############################################################
+
+sub read_password() {
+ open PASS, $PASSWORDFILE
+ or die "Could not read protected password file: $!";
+ my $password = <PASS>;
+ chomp $password;
+ return $password;
+};
+
+############################################################
+
+sub order_chrony($$) {
+ my ($clean_command, $password) = @_;
+ open CHRONY, "| $CHRONY &> /dev/null" or die "could not run $CHRONY: $!\n";
+ print CHRONY "password $password\n";
+ print CHRONY "$clean_command\n";
+ close CHRONY
+ or die "Error running command $clean_command\n", "\ton $CHRONY: $!\n";
+}
+
+############################################################
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644
index 0000000..1777da5
--- /dev/null
+++ b/doc/Makefile.in
@@ -0,0 +1,76 @@
+ADOC = asciidoctor
+ADOC_FLAGS =
+SED = sed
+HTML_TO_TXT = w3m -dump -T text/html
+
+MAN_FILES = chrony.conf.man chronyc.man chronyd.man
+TXT_FILES = faq.txt installation.txt
+HTML_FILES = $(MAN_FILES:%.man=%.html) $(TXT_FILES:%.txt=%.html)
+MAN_IN_FILES = $(MAN_FILES:%.man=%.man.in)
+
+SYSCONFDIR = @SYSCONFDIR@
+BINDIR = @BINDIR@
+SBINDIR = @SBINDIR@
+MANDIR = @MANDIR@
+DOCDIR = @DOCDIR@
+CHRONYRUNDIR = @CHRONYRUNDIR@
+CHRONYVARDIR = @CHRONYVARDIR@
+CHRONY_VERSION = @CHRONY_VERSION@
+DEFAULT_USER = @DEFAULT_USER@
+DEFAULT_HWCLOCK_FILE = @DEFAULT_HWCLOCK_FILE@
+DEFAULT_PID_FILE = @DEFAULT_PID_FILE@
+DEFAULT_RTC_DEVICE = @DEFAULT_RTC_DEVICE@
+
+SED_COMMANDS = "s%\@SYSCONFDIR\@%$(SYSCONFDIR)%g;\
+ s%\@BINDIR\@%$(BINDIR)%g;\
+ s%\@SBINDIR\@%$(SBINDIR)%g;\
+ s%\@CHRONY_VERSION\@%$(CHRONY_VERSION)%g;\
+ s%\@DEFAULT_HWCLOCK_FILE\@%$(DEFAULT_HWCLOCK_FILE)%g;\
+ s%\@DEFAULT_PID_FILE\@%$(DEFAULT_PID_FILE)%g;\
+ s%\@DEFAULT_RTC_DEVICE\@%$(DEFAULT_RTC_DEVICE)%g;\
+ s%\@DEFAULT_USER\@%$(DEFAULT_USER)%g;\
+ s%\@CHRONYRUNDIR\@%$(CHRONYRUNDIR)%g;\
+ s%\@CHRONYVARDIR\@%$(CHRONYVARDIR)%g;"
+
+man: $(MAN_FILES) $(MAN_IN_FILES)
+html: $(HTML_FILES)
+txt: $(TXT_FILES)
+docs: man html
+
+%.html: %.adoc
+ $(ADOC) $(ADOC_FLAGS) -b html -o - $< | $(SED) -e $(SED_COMMANDS) > $@
+
+%.man.in: %.adoc
+ $(ADOC) $(ADOC_FLAGS) -b manpage -o $@ $<
+
+%.man: %.man.in
+ $(SED) -e $(SED_COMMANDS) < $< > $@
+
+%.txt: %.html
+ $(HTML_TO_TXT) < $< > $@
+
+install: $(MAN_FILES)
+ [ -d $(DESTDIR)$(MANDIR)/man1 ] || mkdir -p $(DESTDIR)$(MANDIR)/man1
+ [ -d $(DESTDIR)$(MANDIR)/man5 ] || mkdir -p $(DESTDIR)$(MANDIR)/man5
+ [ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8
+ cp chronyc.man $(DESTDIR)$(MANDIR)/man1/chronyc.1
+ chmod 644 $(DESTDIR)$(MANDIR)/man1/chronyc.1
+ cp chronyd.man $(DESTDIR)$(MANDIR)/man8/chronyd.8
+ chmod 644 $(DESTDIR)$(MANDIR)/man8/chronyd.8
+ cp chrony.conf.man $(DESTDIR)$(MANDIR)/man5/chrony.conf.5
+ chmod 644 $(DESTDIR)$(MANDIR)/man5/chrony.conf.5
+
+install-docs: $(HTML_FILES)
+ [ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
+ for f in $(HTML_FILES); do \
+ cp $$f $(DESTDIR)$(DOCDIR); \
+ chmod 644 $(DESTDIR)$(DOCDIR)/$$f; \
+ done
+
+clean:
+ rm -f $(MAN_FILES) $(TXT_FILES) $(HTML_FILES)
+ rm -f $(MAN_IN_FILES)
+
+distclean:
+ rm -f $(MAN_FILES) $(TXT_FILES) $(HTML_FILES)
+ rm -f Makefile
diff --git a/doc/chrony.conf.adoc b/doc/chrony.conf.adoc
new file mode 100644
index 0000000..4b1239f
--- /dev/null
+++ b/doc/chrony.conf.adoc
@@ -0,0 +1,2460 @@
+// This file is part of chrony
+//
+// Copyright (C) Richard P. Curnow 1997-2003
+// Copyright (C) Stephen Wadeley 2016
+// Copyright (C) Bryan Christianson 2017
+// Copyright (C) Miroslav Lichvar 2009-2017
+//
+// 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.
+
+= chrony.conf(5)
+:doctype: manpage
+:man manual: Configuration Files
+:man source: chrony @CHRONY_VERSION@
+
+== NAME
+chrony.conf - chronyd configuration file
+
+== SYNOPSIS
+*chrony.conf*
+
+== DESCRIPTION
+
+This file configures the *chronyd* daemon. The compiled-in location is
+_@SYSCONFDIR@/chrony.conf_, but other locations can be specified on the
+*chronyd* command line with the *-f* option.
+
+Each directive in the configuration file is placed on a separate line. The
+following sections describe each of the directives in turn. The directives can
+occur in any order in the file and they are not case-sensitive.
+
+The configuration directives can also be specified directly on the *chronyd*
+command line. In this case each argument is parsed as a new line and the
+configuration file is ignored.
+
+While the number of supported directives is large, only a few of them are
+typically needed. See the <<examples,*EXAMPLES*>> section for configuration in
+typical operating scenarios.
+
+The configuration file might contain comment lines. A comment line is any line
+that starts with zero or more spaces followed by any one of the following
+characters: *!*, *;*, *#*, *%*. Any line with this format will be ignored.
+
+== DIRECTIVES
+
+=== Time sources
+
+[[server]]*server* _hostname_ [_option_]...::
+The *server* directive specifies an NTP server which can be used as a time
+source. The client-server relationship is strictly hierarchical: a client might
+synchronise its system time to that of the server, but the server's system time
+will never be influenced by that of a client.
++
+The *server* directive is immediately followed by either the name of the
+server, or its IP address. The *server* directive supports the following
+options:
++
+*minpoll* _poll_:::
+This option specifies the minimum interval between requests sent to the server
+as a power of 2 in seconds. For example, *minpoll 5* would mean that the
+polling interval should not drop below 32 seconds. The default is 6 (64
+seconds), the minimum is -6 (1/64th of a second), and the maximum is 24 (6
+months). Note that intervals shorter than 6 (64 seconds) should generally not
+be used with public servers on the Internet, because it might be considered
+abuse. A sub-second interval will be enabled only when the server is reachable
+and the round-trip delay is shorter than 10 milliseconds, i.e. the server
+should be in a local network.
+*maxpoll* _poll_:::
+This option specifies the maximum interval between requests sent to the server
+as a power of 2 in seconds. For example, *maxpoll 9* indicates that the polling
+interval should stay at or below 9 (512 seconds). The default is 10 (1024
+seconds), the minimum is -6 (1/64th of a second), and the maximum is 24 (6
+months).
+*iburst*:::
+With this option, the interval between the first four requests sent to the
+server will be 2 seconds or less instead of the interval specified by the
+*minpoll* option, which allows *chronyd* to make the first update of the clock
+shortly after start.
+*burst*:::
+With this option, *chronyd* will shorten the interval between up to four
+requests to 2 seconds or less when it cannot get a good measurement from the
+server. The number of requests in the burst is limited by the current polling
+interval to keep the average interval at or above the minimum interval, i.e.
+the current interval needs to be at least two times longer than the minimum
+interval in order to allow a burst with two requests.
+*key* _ID_:::
+The NTP protocol supports a message authentication code (MAC) to prevent
+computers having their system time upset by rogue packets being sent to them.
+The MAC is generated as a function of a password specified in the key file,
+which is specified by the <<keyfile,*keyfile*>> directive.
++
+The *key* option specifies which key (with an ID in the range 1 through 2^32-1)
+should *chronyd* use to authenticate requests sent to the server and verify its
+responses. The server must have the same key for this number configured,
+otherwise no relationship between the computers will be possible.
++
+If the server is running *ntpd* and the output size of the hash function used
+by the key is longer than 160 bits (e.g. SHA256), the *version* option needs to
+be set to 4 for compatibility.
+*maxdelay* _delay_:::
+*chronyd* uses the network round-trip delay to the server to determine how
+accurate a particular measurement is likely to be. Long round-trip delays
+indicate that the request, or the response, or both were delayed. If only one
+of the messages was delayed the measurement error is likely to be substantial.
++
+For small variations in the round-trip delay, *chronyd* uses a weighting scheme
+when processing the measurements. However, beyond a certain level of delay the
+measurements are likely to be so corrupted as to be useless. (This is
+particularly so on dial-up or other slow links, where a long delay probably
+indicates a highly asymmetric delay caused by the response waiting behind a lot
+of packets related to a download of 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*
+option. For example, *maxdelay 0.3* would indicate that measurements with a
+round-trip delay of 0.3 seconds or more should be ignored. The default value is
+3 seconds and the maximum value is 1000 seconds.
+*maxdelayratio* _ratio_:::
+This option is similar to the *maxdelay* option above. *chronyd* keeps a record
+of the minimum round-trip delay amongst the previous measurements that it has
+buffered. If a measurement has a round trip delay that is greater than the
+maxdelayratio times the minimum delay, it will be rejected.
+*maxdelaydevratio* _ratio_:::
+If a measurement has a ratio of the increase in the round-trip delay from the
+minimum delay amongst the previous measurements to the standard deviation of
+the previous measurements that is greater than the specified ratio, it will be
+rejected. The default is 10.0.
+*mindelay* _delay_:::
+This option specifies a fixed minimum round-trip delay to be used instead of
+the minimum amongst the previous measurements. This can be useful in networks
+with static configuration to improve the stability of corrections for
+asymmetric jitter, weighting of the measurements, and the *maxdelayratio* and
+*maxdelaydevratio* tests. The value should be set accurately in order to have a
+positive effect on the synchronisation.
+*asymmetry* _ratio_:::
+This option specifies the asymmetry of the network jitter on the path to the
+source, which is used to correct the measured offset according to the delay.
+The asymmetry can be between -0.5 and +0.5. A negative value means the delay of
+packets sent to the source is more variable than the delay of packets sent from
+the source back. By default, *chronyd* estimates the asymmetry automatically.
+*offset* _offset_:::
+This option specifies a correction (in seconds) which will be applied to
+offsets measured with this source. It's particularly useful to compensate for a
+known asymmetry in network delay or timestamping errors. For example, if
+packets sent to the source were on average delayed by 100 microseconds more
+than packets sent from the source back, the correction would be -0.00005 (-50
+microseconds). The default is 0.0.
+*minsamples* _samples_:::
+Set the minimum number of samples kept for this source. This overrides the
+<<minsamples,*minsamples*>> directive.
+*maxsamples* _samples_:::
+Set the maximum number of samples kept for this source. This overrides the
+<<maxsamples,*maxsamples*>> directive.
+*filter* _samples_:::
+This option enables a median filter to reduce noise in NTP measurements. The
+filter will reduce the specified number of samples to a single sample. It is
+intended to be used with very short polling intervals in local networks where
+it is acceptable to generate a lot of NTP traffic.
+*offline*:::
+If the server will not be reachable when *chronyd* is started, the *offline*
+option can be specified. *chronyd* will not try to poll the server until it is
+enabled to do so (by using the <<chronyc.adoc#online,*online*>> command in
+*chronyc*).
+*auto_offline*:::
+With this option, the server will be assumed to have gone offline when sending
+a request fails, e.g. due to a missing route to the network. This option avoids
+the need to run the <<chronyc.adoc#offline,*offline*>> command from *chronyc*
+when disconnecting the network link. (It will still be necessary to use the
+<<chronyc.adoc#online,*online*>> command when the link has been established, to
+enable measurements to start.)
+*prefer*:::
+Prefer this source over sources without the *prefer* option.
+*noselect*:::
+Never select this source. This is particularly useful for monitoring.
+*trust*:::
+Assume time from this source is always true. It can be rejected as a
+falseticker in the source selection only if another source with this option
+does not agree with it.
+*require*:::
+Require that at least one of the sources specified with this option is
+selectable (i.e. recently reachable and not a falseticker) before updating the
+clock. Together with the *trust* option this might be useful to allow a trusted
+authenticated source to be safely combined with unauthenticated sources in
+order to improve the accuracy of the clock. They can be selected and used for
+synchronisation only if they agree with the trusted and required source.
+*xleave*:::
+This option enables an interleaved mode which allows the server or the peer to
+send transmit timestamps captured after the actual transmission (e.g. when the
+server or the peer is running *chronyd* with software (kernel) or hardware
+timestamping). This can significantly improve the accuracy of the measurements.
++
+The interleaved mode is compatible with servers that support only the basic
+mode, but peers must both support and have enabled the interleaved mode,
+otherwise the synchronisation will work only in one direction. Note that even
+servers that support the interleaved mode might respond in the basic mode as
+the interleaved mode requires the servers to keep some state for each client
+and the state might be dropped when there are too many clients (e.g.
+<<clientloglimit,*clientloglimit*>> is too small), or it might be overwritten
+by other clients that have the same IP address (e.g. computers behind NAT or
+someone sending requests with a spoofed source address).
++
+The *xleave* option can be combined with the *presend* option in order to
+shorten the interval in which the server has to keep the state to be able to
+respond in the interleaved mode.
+*polltarget* _target_:::
+Target number of measurements to use for the regression algorithm which
+*chronyd* will try to maintain by adjusting the polling interval between
+*minpoll* and *maxpoll*. A higher target makes *chronyd* prefer shorter polling
+intervals. The default is 8 and a useful range is from 6 to 60.
+*port* _port_:::
+This option allows the UDP port on which the server understands NTP requests to
+be specified. For normal servers this option should not be required (the
+default is 123, the standard NTP port).
+*presend* _poll_:::
+If the timing measurements being made by *chronyd* are the only network data
+passing between two computers, you might find that some measurements are badly
+skewed due to either the client or the server having to do an ARP lookup on the
+other party prior to transmitting a packet. This is more of a problem with long
+sampling intervals, which might be similar in duration to the lifetime of entries
+in the ARP caches of the machines.
++
+In order to avoid this problem, the *presend* option can be used. It takes a
+single integer argument, which is the smallest polling interval for which an
+extra pair of NTP packets will be exchanged between the client and the server
+prior to the actual measurement. For example, with the following option
+included in a *server* directive:
++
+----
+presend 9
+----
++
+when the polling interval is 512 seconds or more, an extra NTP client packet
+will be sent to the server a short time (2 seconds) before making the actual
+measurement.
++
+The *presend* option cannot be used in the *peer* directive. If it is used
+with the *xleave* option, *chronyd* will send two extra packets instead of one.
+*minstratum* _stratum_:::
+When the synchronisation source is selected from available sources, sources
+with lower stratum are normally slightly preferred. This option can be used to
+increase stratum of the source to the specified minimum, so *chronyd* will
+avoid selecting that source. This is useful with low stratum sources that are
+known to be unreliable or inaccurate and which should be used only when other
+sources are unreachable.
+*version* _version_:::
+This option sets the NTP version of packets sent to the server. This can be
+useful when the server runs an old NTP implementation that does not respond to
+requests using a newer version. The default version depends on whether a key is
+specified by the *key* option and which authentication hash function the key
+is using. If the output size of the hash function is longer than 160 bits, the
+default version is 3 for compatibility with older *chronyd* servers. Otherwise,
+the default version is 4.
+
+[[pool]]*pool* _name_ [_option_]...::
+The syntax of this directive is similar to that for the <<server,*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 might change over time.
++
+All options valid in the <<server,*server*>> directive can be used in this
+directive too. There is one option specific to the *pool* directive:
+*maxsources* sets the maximum number of sources that can be used from the pool,
+the default value is 4.
++
+On start, when the pool name is resolved, *chronyd* will add up to 16 sources,
+one for each resolved address. When the number of sources from which at least
+one valid reply was received reaches the number specified by the *maxsources*
+option, the other sources will be removed. When a pool source is unreachable,
+marked as a falseticker, or has a distance larger than the limit set by the
+<<maxdistance,*maxdistance*>> directive, *chronyd* will try to replace the
+source with a newly resolved address from the pool.
++
+An example of the *pool* directive is
++
+----
+pool pool.ntp.org iburst maxsources 3
+----
+
+[[peer]]*peer* _hostname_ [_option_]...::
+The syntax of this directive is identical to that for the <<server,*server*>>
+directive, except that it specifies a symmetric association with an NTP peer
+instead of a client/server association with an NTP server. A single symmetric
+association allows the peers to be both servers and clients to each other. This
+is mainly useful when the NTP implementation of the peer (e.g. *ntpd*) supports
+ephemeral symmetric associations and does not need to be configured with an
+address of this host. *chronyd* does not support ephemeral associations.
++
+When a key is specified by the *key* option to enable authentication, both
+peers must use the same key and the same key number.
++
+Note that the symmetric mode is less secure than the client/server mode. A
+denial-of-service attack is possible on unauthenticated symmetric associations,
+i.e. when the peer was specified without the *key* option. An attacker who does
+not see network traffic between two hosts, but knows that they are peering with
+each other, can periodically send them unauthenticated packets with spoofed
+source addresses in order to disrupt their NTP state and prevent them from
+synchronising to each other. When the association is authenticated, an attacker
+who does see the network traffic, but cannot prevent the packets from reaching
+the other host, can still disrupt the state by replaying old packets. The
+attacker has effectively the same power as a man-in-the-middle attacker. A
+partial protection against this attack is implemented in *chronyd*, which can
+protect the peers if they are using the same polling interval and they never
+sent an authenticated packet with a timestamp from future, but it should not be
+relied on as it is difficult to ensure the conditions are met. If two hosts
+should be able to synchronise to each other in both directions, it is
+recommended to use two separate client/server associations (specified by the
+<<server,*server*>> directive on both hosts) instead.
+
+[[initstepslew]]*initstepslew* _step-threshold_ [_hostname_]...::
+In normal operation, *chronyd* slews the time when it needs to adjust the
+system clock. For example, to correct a system clock which is 1 second slow,
+*chronyd* slightly increases the amount by which the system clock is advanced
+on each clock interrupt, until the error is removed. Note that at no time does
+time run backwards with this method.
++
+On most Unix systems it is not desirable to step the system clock, because many
+programs rely on time advancing monotonically forwards.
++
+When the *chronyd* daemon is initially started, it is possible that the system
+clock is considerably in error. Attempting to correct such an error by slewing
+might not be sensible, since it might take several hours to correct the error by
+this means.
++
+The purpose of the *initstepslew* directive is to allow *chronyd* to make a
+rapid measurement of the system clock error at boot time, and to correct the
+system clock by stepping before normal operation begins. Since this would
+normally be performed only at an appropriate point in the system boot sequence,
+no other software should be adversely affected by the step.
++
+If the correction required is less than a specified threshold, a slew is used
+instead. This makes it safer to restart *chronyd* whilst the system is in
+normal operation.
++
+The *initstepslew* directive takes a threshold and a list of NTP 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 the use of the directive is:
++
+----
+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, a slew will be used to
+correct it; if the error is above 30 seconds, a step will be used.
++
+The *initstepslew* directive can also be used in an isolated LAN environment,
+where the clocks are set manually. The most stable computer is chosen as the
+master, and the other computers are slaved to it. If each of the slaves is
+configured with the <<local,*local*>> directive, the master can be set up with
+an *initstepslew* directive which references some or all of the slaves. Then,
+if the master machine has to be rebooted, the slaves can be relied on to act
+analogously to a flywheel and preserve the time for a short period while the
+master completes its reboot.
++
+The *initstepslew* directive is functionally similar to a combination of the
+<<makestep,*makestep*>> and <<server,*server*>> directives with the *iburst*
+option. The main difference is that the *initstepslew* servers are used only
+before normal operation begins and that the foreground *chronyd* process waits
+for *initstepslew* to finish before exiting. This is useful to prevent programs
+started in the boot sequence after *chronyd* from reading the clock before it
+has been stepped.
+
+[[refclock]]*refclock* _driver_ _parameter_[:__option__,...] [_option_]...::
+The *refclock* directive specifies a hardware reference clock to be used as a
+time source. It has two mandatory parameters, a driver name and a
+driver-specific parameter. The two parameters are followed by zero or more
+refclock options. Some drivers have special options, which can be appended to
+the driver-specific parameter (separated by the *:* and *,* characters).
++
+There are four drivers included in *chronyd*:
++
+*PPS*:::
+Driver for the kernel PPS (pulse per second) API. The parameter is the path to
+the PPS device (typically _/dev/pps?_). As PPS refclocks do not supply full
+time, another time source (e.g. NTP server or non-PPS refclock) is needed to
+complete samples from the PPS refclock. An alternative is to enable the
+<<local,*local*>> directive to allow synchronisation with some unknown but
+constant offset. The driver supports the following option:
++
+*clear*::::
+By default, the PPS refclock uses assert events (rising edge) for
+synchronisation. With this option, it will use clear events (falling edge)
+instead.
++
+:::
+Examples:
++
+----
+refclock PPS /dev/pps0 lock NMEA refid GPS
+refclock SHM 0 offset 0.5 delay 0.2 refid NMEA noselect
+refclock PPS /dev/pps1:clear refid GPS2
+----
++
+*SHM*:::
+NTP shared memory driver. This driver uses a shared memory segment to receive
+samples from another process (e.g. *gpsd*). The parameter is the number of the
+shared memory segment, typically a small number like 0, 1, 2, or 3. The driver
+supports the following option:
++
+*perm*=_mode_::::
+This option specifies the permissions of the shared memory segment created by
+*chronyd*. They are specified as a numeric mode. The default value is 0600
+(read-write access for owner only).
+:::
++
+Examples:
++
+----
+refclock SHM 0 poll 3 refid GPS1
+refclock SHM 1:perm=0644 refid GPS2
+----
++
+*SOCK*:::
+Unix domain socket driver. It is similar to the SHM driver, but samples are
+received from a Unix domain socket instead of shared memory and the messages
+have a different format. The parameter is the path to the socket, which
+*chronyd* creates on start. An advantage over the SHM driver is that SOCK does
+not require polling and it can receive PPS samples with incomplete time. The
+format of the messages is described in the _refclock_sock.c_ file in the chrony
+source code.
++
+An application which supports the SOCK protocol is the *gpsd* daemon. The path
+where *gpsd* expects the socket to be created is described in the *gpsd(8)* man
+page. For example:
++
+----
+refclock SOCK /var/run/chrony.ttyS0.sock
+----
++
+*PHC*:::
+PTP hardware clock (PHC) driver. The parameter is the path to the device of
+the PTP clock which should be used as a time source. If the clock is kept in
+TAI instead of UTC (e.g. it is synchronised by a PTP daemon), the current
+UTC-TAI offset needs to be specified by the *offset* option. Alternatively, the
+*pps* refclock option can be enabled to treat the PHC as a PPS refclock, using
+only the sub-second offset for synchronisation. The driver supports the
+following options:
++
+*nocrossts*::::
+This option disables use of precise cross timestamping.
+*extpps*::::
+This option enables a PPS mode in which the PTP clock is timestamping pulses
+of an external PPS signal connected to the clock. The clock does not need to be
+synchronised, but another time source is needed to complete the PPS samples.
+Note that some PTP clocks cannot be configured to timestamp only assert or
+clear events, and it is necessary to use the *width* option to filter wrong
+PPS samples.
+*pin*=_index_::::
+This option specifies the index of the pin to which is connected the PPS
+signal. The default value is 0.
+*channel*=_index_::::
+This option specifies the index of the channel for the PPS mode. The default
+value is 0.
+*clear*::::
+This option enables timestamping of clear events (falling edge) instead of
+assert events (rising edge) in the PPS mode. This may not work with some
+clocks.
+:::
++
+Examples:
++
+----
+refclock PHC /dev/ptp0 poll 0 dpoll -2 offset -37
+refclock PHC /dev/ptp1:nocrossts poll 3 pps
+refclock PHC /dev/ptp2:extpps,pin=1 width 0.2 poll 2
+----
++
+::
+The *refclock* directive supports the following options:
++
+*poll* _poll_:::
+Timestamps produced by refclock drivers are not used immediately, but they are
+stored and processed by a median filter in the polling interval specified by
+this option. This is defined as a power of 2 and can be negative to specify a
+sub-second interval. The default is 4 (16 seconds). A shorter interval allows
+*chronyd* to react faster to changes in the frequency of the system clock, but
+it might have a negative effect on its accuracy if the samples have a lot of
+jitter.
+*dpoll* _dpoll_:::
+Some drivers do not listen for external events and try to produce samples in
+their own polling interval. This is defined as a power of 2 and can be negative
+to specify a sub-second interval. The default is 0 (1 second).
+*refid* _refid_:::
+This option is used to specify the reference ID of the refclock, as up to four
+ASCII characters. The default reference ID is composed from the first three
+characters of the driver name and the number of the refclock. Each refclock
+must have a unique reference ID.
+*lock* _refid_:::
+This option can be used to lock a PPS refclock to another refclock, which is
+specified by its reference ID. In this mode received PPS samples are paired
+directly with raw samples from the specified refclock.
+*rate* _rate_:::
+This option sets the rate of the pulses in the PPS signal (in Hz). This option
+controls how the pulses will be completed with real time. To actually receive
+more than one pulse per second, a negative *dpoll* has to be specified (-3 for
+a 5Hz signal). The default is 1.
+*maxlockage* _pulses_:::
+This option specifies in number of pulses how old can be samples from the
+refclock specified by the *lock* option to be paired with the pulses.
+Increasing this value is useful when the samples are produced at a lower rate
+than the pulses. The default is 2.
+*width* _width_:::
+This option specifies the width of the pulses (in seconds). It is used to
+filter PPS samples when the driver provides samples for both rising and falling
+edges. Note that it reduces the maximum allowed error of the time source which
+completes the PPS samples. If the duty cycle is configurable, 50% should be
+preferred in order to maximise the allowed error.
+*pps*:::
+This options forces *chronyd* to treat any refclock (e.g. SHM or PHC) as a PPS
+refclock. This can be useful when the refclock provides time with a variable
+offset of a whole number of seconds (e.g. it uses TAI instead of UTC). Another
+time source is needed to complete samples from the refclock.
+*offset* _offset_:::
+This option can be used to compensate for a constant error. The specified
+offset (in seconds) is applied to all samples produced by the reference clock.
+The default is 0.0.
+*delay* _delay_:::
+This option sets the NTP delay of the source (in seconds). Half of this value
+is included in the maximum assumed error which is used in the source selection
+algorithm. Increasing the delay is useful to avoid having no majority in the
+source selection or to make it prefer other sources. The default is 1e-9 (1
+nanosecond).
+*stratum* _stratum_:::
+This option sets the NTP stratum of the refclock. This can be useful when the
+refclock provides time with a stratum other than 0. The default is 0.
+*precision* _precision_:::
+This option sets the precision of the reference clock (in seconds). The default
+value is the estimated precision of the system clock.
+*maxdispersion* _dispersion_:::
+Maximum allowed dispersion for filtered samples (in seconds). Samples with
+larger estimated dispersion are ignored. By default, this limit is disabled.
+*filter* _samples_:::
+This option sets the length of the median filter which is used to reduce the
+noise in the measurements. With each poll about 40 percent of the stored
+samples are discarded and one final sample is calculated as an average of the
+remaining samples. If the length is 4 or more, at least 4 samples have to be
+collected between polls. For lengths below 4, the filter has to be full. The
+default is 64.
+*prefer*:::
+Prefer this source over sources without the prefer option.
+*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.
+*trust*:::
+Assume time from this source is always true. It can be rejected as a
+falseticker in the source selection only if another source with this option
+does not agree with it.
+*require*:::
+Require that at least one of the sources specified with this option is
+selectable (i.e. recently reachable and not a falseticker) before updating the
+clock. Together with the *trust* option this can be useful to allow a trusted,
+but not very precise, reference clock to be safely combined with
+unauthenticated NTP sources in order to improve the accuracy of the clock. They
+can be selected and used for synchronisation only if they agree with the
+trusted and required source.
+*tai*:::
+This option indicates that the reference clock keeps time in TAI instead of UTC
+and that *chronyd* should correct its offset by the current TAI-UTC offset. The
+<<leapsectz,*leapsectz*>> directive must be used with this option and the
+database must be kept up to date in order for this correction to work as
+expected. This option does not make sense with PPS refclocks.
+*minsamples* _samples_:::
+Set the minimum number of samples kept for this source. This overrides the
+<<minsamples,*minsamples*>> directive.
+*maxsamples* _samples_:::
+Set the maximum number of samples kept for this source. This overrides the
+<<maxsamples,*maxsamples*>> directive.
+
+[[manual]]*manual*::
+The *manual* directive enables support at run-time for the
+<<chronyc.adoc#settime,*settime*>> command in *chronyc*. If no *manual*
+directive is included, any attempt to use the *settime* command in *chronyc*
+will be met with an error message.
++
+Note that the *settime* command can be enabled at run-time using
+the <<chronyc.adoc#manual,*manual*>> command in *chronyc*. (The idea of the 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.)
+
+[[acquisitionport]]*acquisitionport* _port_::
+By default, *chronyd* uses a separate client socket for each configured server
+and their source port is chosen arbitrarily by the operating system. However,
+you can use the *acquisitionport* directive to explicitly specify a port and
+use only one socket (per IPv4 or IPv6 address family) for all configured servers.
+This can be useful for getting through some firewalls. If set to 0, the source
+port of the socket will be chosen arbitrarily.
++
+It can be set to the same port as is used by the NTP server (which can be
+configured with the <<port,*port*>> directive) to use only one socket for all
+NTP packets.
++
+An example of the *acquisitionport* directive is:
++
+----
+acquisitionport 1123
+----
++
+This would change the source port used for client requests to UDP port 1123.
+You could then persuade the firewall administrator to open that port.
+
+[[bindacqaddress]]*bindacqaddress* _address_::
+The *bindacqaddress* directive sets the network interface to which
+*chronyd* will bind its NTP client sockets. The syntax is similar to the
+<<bindaddress,*bindaddress*>> and <<bindcmdaddress,*bindcmdaddress*>>
+directives.
++
+For each of the IPv4 and IPv6 protocols, only one *bindacqaddress* directive
+can be specified.
+
+[[dumpdir]]*dumpdir* _directory_::
+To compute the rate of gain or loss of time, *chronyd* has to store a
+measurement history for each of the time sources it uses.
++
+All supported systems, with the exception of macOS 10.12 and earlier, have
+operating system support for setting the rate of gain or loss to compensate for
+known errors.
+(On macOS 10.12 and earlier, *chronyd* must simulate such a capability by
+periodically slewing the system clock forwards or backwards by a suitable amount
+to compensate for the error built up since the previous slew.)
++
+For such systems, it is possible to save the measurement history across
+restarts of *chronyd* (assuming no changes are made to the system clock
+behaviour whilst it is not running). The *dumpdir* directive defines the
+directory where the measurement histories are saved when *chronyd* exits,
+or the <<chronyc.adoc#dump,*dump*>> command in *chronyc* is issued.
++
+An example of the directive is:
++
+----
+dumpdir @CHRONYRUNDIR@
+----
++
+A source whose IP address is _1.2.3.4_ would have its measurement history saved
+in the file _@CHRONYRUNDIR@/1.2.3.4.dat_. History of reference clocks is saved
+to files named by their reference ID in form of _refid:XXXXXXXX.dat_.
+
+[[maxsamples]]*maxsamples* _samples_::
+The *maxsamples* directive sets the default maximum number of samples that
+*chronyd* should keep for each source. This setting can be overridden for
+individual sources in the <<server,*server*>> and <<refclock,*refclock*>>
+directives. The default value is 0, which disables the configurable limit. The
+useful range is 4 to 64.
+
+[[minsamples]]*minsamples* _samples_::
+The *minsamples* directive sets the default minimum number of samples that
+*chronyd* should keep for each source. This setting can be overridden for
+individual sources in the <<server,*server*>> and <<refclock,*refclock*>>
+directives. The default value is 6. The useful range is 4 to 64.
++
+Forcing *chronyd* to keep more samples than it would normally keep reduces
+noise in the estimated frequency and offset, but slows down the response to
+changes in the frequency and offset of the clock. The offsets in the
+<<chronyc.adoc#tracking,*tracking*>> and
+<<chronyc.adoc#sourcestats,*sourcestats*>> reports (and the _tracking.log_ and
+_statistics.log_ files) may be smaller than the actual offsets.
+
+=== Source selection
+
+[[combinelimit]]*combinelimit* _limit_::
+When *chronyd* has multiple sources available for synchronisation, it has to
+select one source as the synchronisation source. The measured offsets and
+frequencies of the system clock relative to the other sources, however, can be
+combined with the selected source to improve the accuracy of the system clock.
++
+The *combinelimit* directive limits which sources are included in the combining
+algorithm. Their synchronisation distance has to be shorter than the distance
+of the selected source multiplied by the value of the limit. Also, their
+measured frequencies have to be close to the frequency of the selected source.
++
+By default, the limit is 3. Setting the limit to 0 effectively disables the
+source combining algorithm and only the selected source will be used to control
+the system clock.
+
+[[maxdistance]]*maxdistance* _distance_::
+The *maxdistance* directive sets the maximum allowed root distance of the
+sources to not be rejected by the source selection algorithm. The distance
+includes the accumulated dispersion, which might be large when the source is no
+longer synchronised, and half of the total round-trip delay to the primary
+source.
++
+By default, the maximum root distance is 3 seconds.
++
+Setting *maxdistance* to a larger value can be useful to allow synchronisation
+with a server that only has a very infrequent connection to its sources and can
+accumulate a large dispersion between updates of its clock.
+
+[[maxjitter]]*maxjitter* _jitter_::
+The *maxjitter* directive sets the maximum allowed jitter of the sources to not
+be rejected by the source selection algorithm. This prevents synchronisation
+with sources that have a small root distance, but their time is too variable.
++
+By default, the maximum jitter is 1 second.
+
+[[minsources]]*minsources* _sources_::
+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 incorrect time) is
+reachable.
+
+[[reselectdist]]*reselectdist* _distance_::
+When *chronyd* selects a synchronisation source from available sources, it
+will prefer the one with the shortest synchronisation distance. However, to
+avoid frequent reselecting when there are sources with similar distance, a
+fixed distance is added to the distance for sources that are currently not
+selected. This can be set with the *reselectdist* directive. By default, the
+distance is 100 microseconds.
+
+[[stratumweight]]*stratumweight* _distance_::
+The *stratumweight* directive sets how much distance should be added per
+stratum to the synchronisation distance when *chronyd* selects the
+synchronisation source from available sources.
++
+By default, the weight is 0.001 seconds. This means that the stratum of the sources
+in the selection process matters only when the differences between the
+distances are in milliseconds.
+
+=== System clock
+
+[[corrtimeratio]]*corrtimeratio* _ratio_::
+When *chronyd* is slewing the system clock to correct an offset, the rate at
+which it is slewing adds to the frequency error of the clock. On all supported
+systems, with the exception of macOS 12 and earlier, this rate can be
+controlled.
++
+The *corrtimeratio* directive sets the ratio between the duration in which the
+clock is slewed for an average correction according to the source history and
+the interval in which the corrections are done (usually the NTP polling
+interval). Corrections larger than the average take less time and smaller
+corrections take more time, the amount of the correction and the correction
+time are inversely proportional.
++
+Increasing *corrtimeratio* improves the overall frequency error of the system
+clock, but increases the overall time error as the corrections take longer.
++
+By default, the ratio is set to 3, the time accuracy of the clock is preferred
+over its frequency accuracy.
++
+The maximum allowed slew rate can be set by the <<maxslewrate,*maxslewrate*>>
+directive. The current remaining correction is shown in the
+<<chronyc.adoc#tracking,*tracking*>> report as the *System time* value.
+
+[[driftfile]]*driftfile* _file_::
+One of the main activities of the *chronyd* program is to work out the rate at
+which the system clock gains or loses time relative to real time.
++
+Whenever *chronyd* computes a new value of the gain or loss rate, it is desirable
+to record it somewhere. This allows *chronyd* to begin compensating the system
+clock at that rate whenever it is restarted, even before it has had a chance to
+obtain an equally good estimate of the rate during the new run. (This process
+can take many minutes, at least.)
++
+The *driftfile* directive allows a file to be specified into which *chronyd*
+can store the rate information. Two parameters are recorded in the file. The
+first is the rate at which the system clock gains or loses time, expressed in
+parts per million, with gains positive. Therefore, a value of 100.0 indicates
+that when the system clock has advanced by a second, it has gained 100
+microseconds in reality (so the true time has only advanced by 999900
+microseconds). The second is an estimate of the error bound around the first
+value in which the true rate actually lies.
++
+An example of the driftfile directive is:
++
+----
+driftfile @CHRONYVARDIR@/drift
+----
+
+[[fallbackdrift]]*fallbackdrift* _min-interval_ _max-interval_::
+Fallback drifts are long-term averages of the system clock drift calculated
+over exponentially increasing intervals. They are used to avoid quickly
+drifting away from true time when the clock was not updated for a longer period
+of time and there was a short-term deviation in the drift before the updates
+stopped.
++
+The directive specifies the minimum and maximum interval since the 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 the maximum interval is
+19 (6 days). The system clock frequency will be set to the first fallback 18
+hours after last clock update, to the second after 36 hours, and so on. This
+might be a good setting to cover frequency changes due to daily and weekly
+temperature fluctuations. When the frequency is set to a fallback, the state of
+the clock will change to '`Not synchronised`'.
++
+By default (or if the specified maximum or minimum is 0), no fallbacks are used
+and the clock frequency changes only with new measurements from NTP sources,
+reference clocks, or manual input.
+
+[[leapsecmode]]*leapsecmode* _mode_::
+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 (i.e. all supported
+systems with the exception of macOS 12 and earlier).
+*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 does not 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 might be
+preferred over the *system* and *step* modes when applications running on the
+system are sensitive to jumps in the system time and it is acceptable that the
+clock will be off for a longer time. On Linux with the default
+<<maxslewrate,*maxslewrate*>> value 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.
+::
++
+When serving time to NTP clients that cannot be configured to correct their
+clocks for a leap second by slewing, or to clients that would correct at
+slightly different rates when it is necessary to keep them close together, the
+*slew* mode can be combined with the <<smoothtime,*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
+do not need any special configuration as they do not know there is any leap
+second and they follow the server time which eventually brings them back to
+UTC. Care must be taken to ensure they use only NTP servers which smear the
+leap second in exactly the same way for synchronisation.
++
+This feature must 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 a 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.
+
+[[leapsectz]]*leapsectz* _timezone_::
+This directive specifies a timezone in the system tz database which *chronyd*
+can use to determine when will the next leap second occur and what is the
+current offset between TAI and UTC. It will periodically check if 23:59:59 and
+23:59:60 are valid times in the timezone. This typically works with the
+_right/UTC_ timezone.
++
+When a leap second is announced, the timezone needs to be updated at least 12
+hours before the leap second. It is not necessary to restart *chronyd*.
++
+This directive is useful with reference clocks and other time sources which do
+not announce leap seconds, or announce them too late for an NTP server to
+forward them to its own clients. Clients of leap smearing servers must not
+use this directive.
++
+It is also useful when the system clock is required to have correct TAI-UTC
+offset. Note that the offset is set only when leap seconds are handled by the
+kernel, i.e. <<leapsecmode,*leapsecmode*>> is set to *system*.
++
+The specified timezone is not used as an exclusive source of information about
+leap seconds. If a majority of time sources announce on the last day of June or
+December that a leap second should be inserted or deleted, it will be accepted
+even if it is not included in the timezone.
++
+An example of the directive is:
++
+----
+leapsectz right/UTC
+----
++
+The following shell command verifies that the timezone contains leap 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
+----
+
+[[makestep]]*makestep* _threshold_ _limit_::
+Normally *chronyd* will cause the system to gradually correct any time offset,
+by slowing down or speeding up the clock as required. In certain situations,
+the system clock might be so far adrift that this slewing process would take a
+very long time to correct the system clock.
++
+This directive forces *chronyd* to step the system clock if the adjustment is
+larger than a threshold value, but only if there were no more clock updates
+since *chronyd* was started than a specified limit (a negative value can be
+used to disable the limit).
++
+This is particularly useful when using reference clocks, because the
+<<initstepslew,*initstepslew*>> directive works only with NTP sources.
++
+An example of the use of this directive is:
++
+----
+makestep 0.1 3
+----
++
+This would step the system clock if the adjustment is larger than 0.1 seconds, but
+only in the first three clock updates.
+
+[[maxchange]]*maxchange* _offset_ _start_ _ignore_::
+This directive sets the maximum allowed offset corrected on a clock update. The
+check is performed only after the specified number of updates to allow a large
+initial adjustment of the system clock. When an offset larger than the
+specified maximum occurs, it will be ignored for the specified number of times
+and then *chronyd* will give up and exit (a negative value can be used to never
+exit). In both cases a message is sent to syslog.
++
+An example of the use of this directive is:
++
+----
+maxchange 1000 1 2
+----
++
+After the first clock update, *chronyd* will check the offset on every clock
+update, it will ignore two adjustments larger than 1000 seconds and exit on
+another one.
+
+[[maxclockerror]]*maxclockerror* _error-in-ppm_::
+The *maxclockerror* directive sets the maximum assumed frequency error that the
+system clock can gain on its own between clock updates. It describes the
+stability of the clock.
++
+By default, the maximum error is 1 ppm.
++
+Typical values for _error-in-ppm_ might be 10 for a low quality clock and 0.1
+for a high quality clock using a temperature compensated crystal oscillator.
+
+[[maxdrift]]*maxdrift* _drift-in-ppm_::
+This directive specifies the maximum assumed drift (frequency error) of the
+system clock. It limits the frequency adjustment that *chronyd* is allowed to
+use to correct the measured drift. It is an additional limit to the maximum
+adjustment that can be set by the system driver (100000 ppm on Linux, 500 ppm
+on FreeBSD, NetBSD, and macOS 10.13+, 32500 ppm on Solaris).
++
+By default, the maximum assumed drift is 500000 ppm, i.e. the adjustment is
+limited by the system driver rather than this directive.
+
+[[maxupdateskew]]*maxupdateskew* _skew-in-ppm_::
+One of *chronyd*'s tasks is to work out how fast or slow the computer's clock
+runs relative to its reference sources. In addition, it computes an estimate of
+the error bounds around the estimated value.
++
+If the range of error is too large, it probably indicates that the measurements
+have not settled down yet, and that the estimated gain or loss rate is not very
+reliable.
++
+The *maxupdateskew* directive sets the threshold for determining whether an
+estimate might be so unreliable that it should not be used. By default, the
+threshold is 1000 ppm.
++
+Typical values for _skew-in-ppm_ might be 100 for a dial-up connection to
+servers over a phone line, and 5 or 10 for a computer on a LAN.
++
+It should be noted that this is not the only means of protection against using
+unreliable estimates. At all times, *chronyd* keeps track of both the estimated
+gain or loss rate, and the error bound on the estimate. When a new estimate is
+generated following another measurement from one of the sources, a weighted
+combination algorithm is used to update the master estimate. So if *chronyd*
+has an existing 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.
+
+[[maxslewrate]]*maxslewrate* _rate-in-ppm_::
+The *maxslewrate* directive sets the maximum rate at which *chronyd* is allowed
+to slew the time. It limits the slew rate controlled by the correction time
+ratio (which can be set by the <<corrtimeratio,*corrtimeratio*>> directive) and
+is effective only on systems where *chronyd* is able to control the rate (i.e.
+all supported systems with the exception of macOS 12 or earlier).
++
+For each system there is a maximum frequency offset of the clock that can be set
+by the driver. On Linux it is 100000 ppm, on FreeBSD, NetBSD and macOS 10.13+ it
+is 5000 ppm, and on Solaris it is 32500 ppm. Also, due to a kernel limitation,
+setting *maxslewrate* on FreeBSD, NetBSD, macOS 10.13+ to a value between 500
+ppm and 5000 ppm will effectively set it to 500 ppm.
++
+In early beta releases of macOS 13 this capability is disabled because of a
+system kernel bug. When the kernel bug is fixed, chronyd will detect this and
+re-enable the capability (see above limitations) with no recompilation required.
++
+By default, the maximum slew rate is set to 83333.333 ppm (one twelfth).
+
+[[tempcomp]]
+*tempcomp* _file_ _interval_ _T0_ _k0_ _k1_ _k2_::
+*tempcomp* _file_ _interval_ _points-file_::
+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 motherboard.
++
+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.
++
+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 the compensation is specified, and
+how close the sensor is to the oscillator. When it is working well, the
+frequency reported in the _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
++
+----
+k0 + (T - T0) * k1 + (T - T0)^2 * k2
+----
++
+The result has to be between -10 ppm and 10 ppm, otherwise the measurement is
+considered invalid and will be ignored. The _k0_ coefficient can be adjusted to
+keep the compensation in that range.
++
+An example of the use is:
++
+----
+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 faster by 0.183 ppm, 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 _/etc/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
+----
++
+Valid measurements with corresponding compensations are logged to the
+_tempcomp.log_ file if enabled by the <<log,*log tempcomp*>> directive.
+
+=== NTP server
+
+[[allow]]*allow* [*all*] [_subnet_]::
+The *allow* directive is used to designate a particular subnet from which NTP
+clients are allowed to access the computer as an NTP server.
++
+The default is that no clients are allowed access, i.e. *chronyd* operates
+purely as an NTP client. If the *allow* directive is used, *chronyd* will be
+both a client of its servers, and a server to other clients.
++
+Examples of the use of the directive are as follows:
++
+----
+allow 1.2.3.4
+allow 1.2
+allow 3.4.5
+allow 6.7.8/22
+allow 6.7.8.9/22
+allow 2001:db8::/32
+allow 0/0
+allow ::/0
+allow
+----
++
+The first directive allows a node with IPv4 address _1.2.3.4_ to be an NTP
+client of this computer.
+The second directive allows any node with an IPv4 address of the form _1.2.x.y_
+(with _x_ and _y_ arbitrary) to be an NTP client of this computer. Likewise,
+the third directive allows any node with an IPv4 address of the form _3.4.5.x_
+to have client NTP access. The fourth and fifth forms allow access from any
+node with an IPv4 address of the form _6.7.8.x_, _6.7.9.x_, _6.7.10.x_ or
+_6.7.11.x_ (with _x_ arbitrary), i.e. the value 22 is the number of bits
+defining the specified subnet. In the fifth form, the final byte is ignored.
+The sixth form is used for IPv6 addresses. The seventh and eighth forms allow
+access by any IPv4 and IPv6 node respectively. The ninth forms allows access by
+any node (IPv4 or IPv6).
++
+A second form of the directive, *allow all*, has a greater effect, depending on
+the ordering of directives in the configuration file. To illustrate the effect,
+consider the two examples:
++
+----
+allow 1.2.3.4
+deny 1.2.3
+allow 1.2
+----
++
+and
++
+----
+allow 1.2.3.4
+deny 1.2.3
+allow all 1.2
+----
++
+In the first example, the effect is the same regardless of what order the three
+directives are given in. So the _1.2.x.y_ subnet is allowed access, except for
+the _1.2.3.x_ subnet, which is denied access, however the host _1.2.3.4_ is
+allowed access.
++
+In the second example, the *allow all 1.2* directives overrides the effect of
+_any_ previous directive relating to a subnet within the specified subnet.
+Within a configuration file this capability is probably rather moot; however,
+it is of greater use for reconfiguration at run-time via *chronyc* with the
+<<chronyc.adoc#allow,*allow all*>> command.
++
+The directive allows a hostname to be specified instead of an IP address, but
+the name must be resolvable when *chronyd* is started (i.e. *chronyd* needs
+to be started when the network is already up and DNS is working).
++
+Note, if the <<initstepslew,*initstepslew*>> directive is used in the
+configuration file, each of the computers listed in that directive must allow
+client access by this computer for it to work.
+
+[[deny]]*deny* [*all*] [_subnet_]::
+This is similar to the <<allow,*allow*>> directive, except that it denies NTP
+client access to a particular subnet or host, rather than allowing it.
++
+The syntax is identical.
++
+There is also a *deny all* directive with similar behaviour to the *allow all*
+directive.
+
+[[bindaddress]]*bindaddress* _address_::
+The *bindaddress* directive binds the socket on which *chronyd* listens for NTP
+requests to a local address of the computer. On systems other than Linux, the
+address of the computer needs to be already configured when *chronyd* is
+started.
++
+An example of the use of the directive is:
++
+----
+bindaddress 192.168.1.1
+----
++
+Currently, for each of the IPv4 and IPv6 protocols, only one *bindaddress*
+directive can be specified. Therefore, it is not useful on computers which
+should serve NTP on multiple network interfaces.
+
+[[broadcast]]*broadcast* _interval_ _address_ [_port_]::
+The *broadcast* directive is used to declare a broadcast address to which
+chronyd should send packets in the NTP broadcast mode (i.e. make *chronyd* act
+as a broadcast server). Broadcast clients on that subnet will be able to
+synchronise.
++
+The syntax is as follows:
++
+----
+broadcast 30 192.168.1.255
+broadcast 60 192.168.2.255 12123
+broadcast 60 ff02::101
+----
++
+In the first example, the destination port defaults to UDP port 123 (the normal NTP
+port). In the second example, the destination port is specified as 12123. The
+first parameter in each case (30 or 60 respectively) is the interval in seconds
+between broadcast packets being sent. The second parameter in each case is the
+broadcast address to send the packet to. This should correspond to the
+broadcast address of one of the network interfaces on the computer where
+*chronyd* is running.
++
+You can have more than 1 *broadcast* directive if you have more than 1 network
+interface onto which you want to send NTP broadcast packets.
++
+*chronyd* itself cannot act as a broadcast client; it must always be configured
+as a point-to-point client by defining specific NTP servers and peers. This
+broadcast server feature is intended for providing a time source to other NTP
+implementations.
++
+If *ntpd* is used as the broadcast client, it will try to measure the
+round-trip delay between the server and client with normal client mode packets.
+Thus, the broadcast subnet should also be the subject of an <<allow,*allow*>>
+directive.
+
+[[clientloglimit]]*clientloglimit* _limit_::
+This directive specifies the maximum amount of memory that *chronyd* is allowed
+to allocate for logging of client accesses and the state that *chronyd* as an
+NTP server needs to support the interleaved mode for its clients. The default
+limit is 524288 bytes, which is sufficient for monitoring about four thousand
+clients at the same time.
++
+In older *chrony* versions if the limit was set to 0, the memory allocation was
+unlimited.
++
+An example of the use of this directive is:
++
+----
+clientloglimit 1048576
+----
+
+[[noclientlog]]*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 <<chronyc.adoc#clients,*clients*>> command in *chronyc*. This option
+also effectively disables server support for the NTP interleaved mode.
+
+[[local]]*local* [_option_]...::
+The *local* directive enables a local reference mode, which allows *chronyd*
+operating as an NTP server to appear synchronised to real time (from the
+viewpoint of clients polling it), even when it was never synchronised or
+the last update of the clock happened a long time ago.
++
+This directive is normally used in an isolated network, where computers are
+required to be synchronised to one another, but not necessarily to real time.
+The server can be kept vaguely in line with real time by manual input.
++
+The *local* directive has the following options:
++
+*stratum* _stratum_:::
+This option sets the stratum of the server which will be reported to clients
+when the local reference is active. The specified value is in the range 1
+through 15, and the default value is 10. It should be larger than the maximum
+expected stratum in the network when external NTP servers are accessible.
++
+Stratum 1 indicates a computer that has a true real-time reference directly
+connected to it (e.g. GPS, atomic clock, etc.), such computers are expected to
+be very close to real time. Stratum 2 computers are those which have a stratum
+1 server; stratum 3 computers have a stratum 2 server and so on. A value
+of 10 indicates that the clock is so many hops away from a reference clock that
+its time is fairly unreliable.
+*distance* _distance_:::
+This option sets the threshold for the root distance which will activate the local
+reference. If *chronyd* was synchronised to some source, the local reference
+will not be activated until its root distance reaches the specified value (the
+rate at which the distance is increasing depends on how well the clock was
+tracking the source). The default value is 1 second.
++
+The current root distance can be calculated from root delay and root dispersion
+(reported by the <<chronyc.adoc#tracking,*tracking*>> command in *chronyc*) as:
++
+----
+distance = delay / 2 + dispersion
+----
+*orphan*:::
+This option enables a special '`orphan`' mode, where sources with stratum equal
+to the local _stratum_ are assumed to not serve real time. They are ignored
+unless no other source is selectable and their reference IDs are smaller than
+the local reference ID.
++
+This allows multiple servers in the network to use the same *local*
+configuration and to be synchronised to one another, without confusing clients
+that poll more than one server. Each server needs to be configured to poll all
+other servers with the *local* directive. This ensures only the server with the
+smallest reference ID has the local reference active and others are
+synchronised to it. When that server fails, another will take over.
++
+The *orphan* mode is compatible with the *ntpd*'s orphan mode (enabled by the
+*tos orphan* command).
+::
++
+An example of the directive is:
++
+----
+local stratum 10 orphan
+----
+
+[[ntpsigndsocket]]*ntpsigndsocket* _directory_::
+This directive specifies the location of the Samba *ntp_signd* socket when it
+is running as a Domain Controller (DC). If *chronyd* is compiled with this
+feature, responses to MS-SNTP clients will be signed by the *smbd* daemon.
++
+Note that MS-SNTP requests are not authenticated and any client that is allowed
+to access the server by the <<allow,*allow*>> directive, or the
+<<chronyc.adoc#allow,*allow*>> command in *chronyc*, can get an MS-SNTP
+response signed with a trust account's password and try to crack the password
+in a brute-force attack. Access to the server should be carefully controlled.
++
+An example of the directive is:
++
+----
+ntpsigndsocket /var/lib/samba/ntp_signd
+----
+
+[[port]]*port* _port_::
+This option allows you to configure the port on which *chronyd* will listen for
+NTP requests. The port will be open only when an address is allowed by the
+<<allow,*allow*>> directive or the <<chronyc.adoc#allow,*allow*>> command in
+*chronyc*, an NTP peer is configured, or the broadcast server mode is enabled.
++
+The default value is 123, the standard NTP port. If set to 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,*acquisitionport*>> directive.
+
+[[ratelimit]]*ratelimit* [_option_]...::
+This directive enables response rate limiting for NTP packets. Its purpose is
+to reduce network traffic with misconfigured or broken NTP clients that are
+polling the server too frequently. The limits are applied to individual IP
+addresses. If multiple clients share one IP address (e.g. multiple hosts behind
+NAT), the sum of their traffic will be limited. If a client that increases its
+polling rate when it does not receive a reply is detected, its rate limiting
+will be temporarily suspended to avoid increasing the overall amount of
+traffic. The maximum number of IP addresses which can be monitored at the same
+time depends on the memory limit set by the <<clientloglimit,*clientloglimit*>>
+directive.
++
+The *ratelimit* directive supports a number of options (which can be defined
+in any order):
++
+*interval*:::
+This option sets the minimum interval between responses. It is defined as a
+power of 2 in seconds. The default value is 3 (8 seconds). The minimum value
+is -19 (524288 packets per second) and the maximum value is 12 (one packet per
+4096 seconds). Note that with values below -4 the rate limiting is coarse
+(responses are allowed in bursts, even if the interval between them is shorter
+than the specified interval).
+*burst*:::
+This option sets the maximum number of responses that can be sent in a burst,
+temporarily exceeding the limit specified by the *interval* option. This is
+useful for clients that make rapid measurements on start (e.g. *chronyd* with
+the *iburst* option). The default value is 8. The minimum value is 1 and the
+maximum value is 255.
+*leak*:::
+This option sets the rate at which responses are randomly allowed even if the
+limits specified by the *interval* and *burst* options are exceeded. This is
+necessary to prevent an attacker who is sending requests with a spoofed
+source address from completely blocking responses to that address. The leak
+rate is defined as a power of 1/2 and it is 2 by default, i.e. on average at
+least every fourth request has a response. The minimum value is 1 and the
+maximum value is 4.
+::
++
+An example use of the directive is:
++
+----
+ratelimit interval 1 burst 16
+----
++
+This would reduce the response rate for IP addresses sending packets on average
+more than once per 2 seconds, or sending packets in bursts of more than 16
+packets, by up to 75% (with default *leak* of 2).
+
+[[smoothtime]]*smoothtime* _max-freq_ _max-wander_ [*leaponly*]::
+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 can take a very long time
+to smooth it out. This directive should be used only when the clients are not
+configured to also poll 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 is 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,*makestep*>> directive or the
+<<chronyc.adoc#makestep,*makestep*>> command in *chronyc*. The process can be
+reset without stepping the clock by the <<chronyc.adoc#smoothtime,*smoothtime
+reset*>> 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 and frequency changes are ignored. The *leaponly*
+option is useful in a combination with the <<leapsecmode,*leapsecmode slew*>>
+directive to allow the clients to 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 <<chronyc.adoc#smoothtime,*smoothtime
+activate*>> command, which is particularly useful when the clock is
+synchronised only with manual input and the skew is always larger than the
+threshold. The <<chronyc.adoc#smoothing,*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
+----
+
+=== Command and monitoring access
+
+[[bindcmdaddress]]*bindcmdaddress* _address_::
+The *bindcmdaddress* directive allows you to specify an IP address of an
+interface on which *chronyd* will listen for monitoring command packets (issued
+by *chronyc*). On systems other than Linux, the address of the interface needs
+to be already configured when *chronyd* is started.
++
+This directive can also change the path of the Unix domain command socket,
+which is used by *chronyc* to send configuration commands. The socket must be
+in a directory that is accessible only by the root or _chrony_ user. The
+directory will be created on start if it does not exist. The compiled-in default
+path of the socket is _@CHRONYRUNDIR@/chronyd.sock_. The socket can be
+disabled by setting the path to _/_.
++
+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 0.0.0.0
+bindcmdaddress ::
+----
++
+to the configuration file.
++
+For each of the IPv4, IPv6, and Unix domain protocols, only one
+*bindcmdaddress* directive can be specified.
++
+An example that sets the path of the Unix domain command socket is:
++
+----
+bindcmdaddress /var/run/chrony/chronyd.sock
+----
+
+[[cmdallow]]*cmdallow* [*all*] [_subnet_]::
+This is similar to the <<allow,*allow*>> directive, except that it allows
+monitoring access (rather than NTP client access) to a particular subnet or
+host. (By '`monitoring access`' is meant that *chronyc* can be run on those
+hosts and retrieve monitoring data from *chronyd* on this computer.)
++
+The syntax is identical to the *allow* directive.
++
+There is also a *cmdallow all* directive with similar behaviour to the *allow
+all* directive (but applying to monitoring access in this case, of course).
++
+Note that *chronyd* has to be configured with the
+<<bindcmdaddress,*bindcmdaddress*>> directive to not listen only on the
+loopback interface to actually allow remote access.
+
+[[cmddeny]]*cmddeny* [*all*] [_subnet_]::
+This is similar to the <<cmdallow,*cmdallow*>> directive, except that it denies
+monitoring access to a particular subnet or host, rather than allowing it.
++
+The syntax is identical.
++
+There is also a *cmddeny all* directive with similar behaviour to the *cmdallow
+all* directive.
+
+[[cmdport]]*cmdport* _port_::
+The *cmdport* directive allows the port that is used for run-time monitoring
+(via the *chronyc* program) to be altered from its default (323). If set to 0,
+*chronyd* will not open the port, this is useful to disable *chronyc*
+access from the Internet. (It does not disable the Unix domain command socket.)
++
+An example shows the syntax:
++
+----
+cmdport 257
+----
++
+This would make *chronyd* use UDP 257 as its command port. (*chronyc* would
+need to be run with the *-p 257* switch to inter-operate correctly.)
+
+[[cmdratelimit]]*cmdratelimit* [_option_]...::
+This directive enables response rate limiting for command packets. It is
+similar to the <<ratelimit,*ratelimit*>> directive, except responses to
+localhost are never limited and the default interval is -4 (16 packets per
+second).
++
+An example of the use of the directive is:
++
+----
+cmdratelimit interval 2
+----
+
+=== Real-time clock (RTC)
+
+[[hwclockfile]]*hwclockfile* _file_::
+The *hwclockfile* directive sets the location of the adjtime file which is
+used by the *hwclock* program on Linux. *chronyd* parses the file to find out
+if the RTC keeps local time or UTC. It overrides the <<rtconutc,*rtconutc*>>
+directive.
++
+The compiled-in default value is '_@DEFAULT_HWCLOCK_FILE@_'.
++
+An example of the directive is:
++
+----
+hwclockfile /etc/adjtime
+----
+
+[[rtcautotrim]]*rtcautotrim* _threshold_::
+The *rtcautotrim* directive is used to keep the RTC close to the system clock
+automatically. When the system clock is synchronised and the estimated error
+between the two clocks is larger than the specified threshold, *chronyd* will
+trim the RTC as if the <<chronyc.adoc#trimrtc,*trimrtc*>> command in *chronyc*
+was issued.
++
+This directive is effective only with the <<rtcfile,*rtcfile*>> directive.
++
+An example of the use of this directive is:
++
+----
+rtcautotrim 30
+----
++
+This would set the threshold error to 30 seconds.
+
+[[rtcdevice]]*rtcdevice* _device_::
+The *rtcdevice* directive sets the path to the device file for accessing the
+RTC. The default path is _@DEFAULT_RTC_DEVICE@_.
+
+[[rtcfile]]*rtcfile* _file_::
+The *rtcfile* directive defines the name of the file in which *chronyd* can
+save parameters associated with tracking the accuracy of the RTC.
++
+An example of the directive is:
++
+----
+rtcfile @CHRONYVARDIR@/rtc
+----
++
+*chronyd* saves information in this file when it exits and when the *writertc*
+command is issued in *chronyc*. The information saved is the RTC's error at
+some epoch, that epoch (in seconds since January 1 1970), and the rate at which
+the RTC gains or loses time.
++
+So far, the support for real-time clocks is limited; their code is even more
+system-specific than the rest of the software. You can only use the RTC
+facilities (the <<rtcfile,*rtcfile*>> directive and the *-s* command-line
+option to *chronyd*) if the following three conditions apply:
++
+. You are running Linux.
+. The kernel is compiled with extended real-time clock support (i.e. the
+ _/dev/rtc_ device is capable of doing useful things).
+. You do not have other applications that need to make use of _/dev/rtc_ at all.
+
+[[rtconutc]]*rtconutc*::
+*chronyd* assumes by default that the RTC keeps local time (including any
+daylight saving changes). This is convenient on PCs running Linux which are
+dual-booted with Windows.
++
+If you keep the RTC on local time and your computer is off when daylight saving
+(summer time) starts or ends, the computer's system time will be one hour in
+error when you next boot and start chronyd.
++
+An alternative is for the RTC to keep Universal Coordinated Time (UTC). This
+does not suffer from the 1 hour problem when daylight saving starts or ends.
++
+If the *rtconutc* directive appears, it means the RTC is required to keep UTC.
+The directive takes no arguments. It is equivalent to specifying the *-u*
+switch to the Linux *hwclock* program.
++
+Note that this setting is overridden when the <<hwclockfile,*hwclockfile*>>
+directive is specified.
+
+[[rtcsync]]*rtcsync*::
+The *rtcsync* directive enables a mode where the system time is periodically
+copied to the RTC and *chronyd* does not try to track its drift. This directive
+cannot be used with the <<rtcfile,*rtcfile*>> directive.
++
+On Linux, the RTC copy is performed by the kernel every 11 minutes.
++
+On macOS, <<chronyd,*chronyd*>> will perform the RTC copy every 60 minutes
+when the system clock is in a synchronised state.
++
+On other systems this directive does nothing.
+
+=== Logging
+
+[[log]]*log* [_option_]...::
+The *log* directive indicates that certain information is to be logged.
+The log files are written to the directory specified by the <<logdir,*logdir*>>
+directive. A banner is periodically written to the files to indicate the
+meanings of the columns.
++
+*rawmeasurements*:::
+This option logs the raw NTP measurements and related information to a file
+called _measurements.log_. An entry is made for each packet received from the
+source. This can be useful when debugging a problem. An example line (which
+actually appears as a single line in the file) from the log file is shown
+below.
++
+----
+2016-11-09 05:40:50 203.0.113.15 N 2 111 111 1111 10 10 1.0 \
+ -4.966e-03 2.296e-01 1.577e-05 1.615e-01 7.446e-03 CB00717B 4B D K
+----
++
+The columns are as follows (the quantities in square brackets are the values
+from the example line above):
++
+. Date [2015-10-13]
+. Hour:Minute:Second. Note that the date-time pair is expressed in UTC, not the
+ local time zone. [05:40:50]
+. IP address of server or peer from which measurement came [203.0.113.15]
+. Leap status (_N_ means normal, _+_ means that the last minute of the current
+ month has 61 seconds, _-_ means that the last minute of the month has 59
+ seconds, _?_ means the remote computer is not currently synchronised.) [N]
+. Stratum of remote computer. [2]
+. RFC 5905 tests 1 through 3 (1=pass, 0=fail) [111]
+. RFC 5905 tests 5 through 7 (1=pass, 0=fail) [111]
+. 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]
+. Local poll [10]
+. Remote poll [10]
+. '`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]
+. The estimated local clock error (_theta_ in RFC 5905). Positive indicates
+ that the local clock is slow of the remote source. [-4.966e-03]
+. The peer delay (_delta_ in RFC 5905). [2.296e-01]
+. The peer dispersion (_epsilon_ in RFC 5905). [1.577e-05]
+. The root delay (_DELTA_ in RFC 5905). [1.615e-01]
+. The root dispersion (_EPSILON_ in RFC 5905). [7.446e-03]
+. Reference ID of the server's source as a hexadecimal number. [CB00717B]
+. NTP mode of the received packet (_1_=active peer, _2_=passive peer,
+ _4_=server, _B_=basic, _I_=interleaved). [4B]
+. Source of the local transmit timestamp
+ (_D_=daemon, _K_=kernel, _H_=hardware). [D]
+. Source of the local receive timestamp
+ (_D_=daemon, _K_=kernel, _H_=hardware). [K]
++
+*measurements*:::
+This option is identical to the *rawmeasurements* option, except it logs only
+valid measurements from synchronised sources, i.e. measurements which passed
+the RFC 5905 tests 1 through 7. This can be useful for producing graphs of the
+source's performance.
++
+*statistics*:::
+This option logs information about the regression processing to a file called
+_statistics.log_. An example line (which actually appears as a single line in
+the file) from the log file is shown below.
++
+----
+2016-08-10 05:40:50 203.0.113.15 6.261e-03 -3.247e-03 \
+ 2.220e-03 1.874e-06 1.080e-06 7.8e-02 16 0 8 0.00
+----
++
+The columns are as follows (the quantities in square brackets are the values
+from the example line above):
++
+. Date [2015-07-22]
+. Hour:Minute:Second. Note that the date-time pair is expressed in
+ UTC, not the local time zone. [05:40:50]
+. IP address of server or peer from which measurement comes [203.0.113.15]
+. The estimated standard deviation of the measurements from the source (in
+ seconds). [6.261e-03]
+. The estimated offset of the source (in seconds, positive means the local
+ clock is estimated to be fast, in this case). [-3.247e-03]
+. The estimated standard deviation of the offset estimate (in seconds).
+ [2.220e-03]
+. The estimated rate at which the local clock is gaining or losing time
+ relative to the source (in seconds per second, positive means the local clock
+ is gaining). This is relative to the compensation currently being applied to
+ the local clock, _not_ to the local clock without any compensation.
+ [1.874e-06]
+. The estimated error in the rate value (in seconds per second). [1.080e-06].
+. The ratio of |old_rate - new_rate| / old_rate_error. Large values
+ indicate the statistics are not modelling the source very well. [7.8e-02]
+. The number of measurements currently being used for the regression
+ algorithm. [16]
+. The new starting index (the oldest sample has index 0; this is the method
+ used to prune old samples when it no longer looks like the measurements fit a
+ linear model). [0, i.e. no samples discarded this time]
+. The number of runs. The number of runs of regression residuals with the same
+ sign is computed. If this is too small it indicates that the measurements are
+ no longer represented well by a linear model and that some older samples need
+ to be discarded. The number of runs for the data that is being retained is
+ tabulated. Values of approximately half the number of samples are expected.
+ [8]
+. The estimated or configured asymmetry of network jitter on the path to the
+ source which was used to correct the measured offsets. The asymmetry can be
+ between -0.5 and +0.5. A negative value means the delay of packets sent to
+ the source is more variable than the delay of packets sent from the source
+ back. [0.00, i.e. no correction for asymmetry]
++
+*tracking*:::
+This option logs changes to the estimate of the system's gain or loss rate, and
+any slews made, to a file called _tracking.log_. An example line (which
+actually appears as a single line in the file) from the log file is shown
+below.
++
+----
+2017-08-22 13:22:36 203.0.113.15 2 -3.541 0.075 -8.621e-06 N \
+ 2 2.940e-03 -2.084e-04 1.534e-02 3.472e-04 8.304e-03
+----
++
+The columns are as follows (the quantities in square brackets are the
+values from the example line above) :
++
+. Date [2017-08-22]
+. Hour:Minute:Second. Note that the date-time pair is expressed in UTC, not the
+ local time zone. [13:22:36]
+. The IP address of the server or peer to which the local system is synchronised.
+ [203.0.113.15]
+. The stratum of the local system. [2]
+. The local system frequency (in ppm, positive means the local system runs fast
+ of UTC). [-3.541]
+. The error bounds on the frequency (in ppm). [0.075]
+. The estimated local offset at the epoch, which is normally corrected by
+ slewing the local clock (in seconds, positive indicates the clock is fast of
+ UTC). [-8.621e-06]
+. Leap status (_N_ means normal, _+_ means that the last minute of this month
+ has 61 seconds, _-_ means that the last minute of the month has 59 seconds,
+ _?_ means the clock is not currently synchronised.) [N]
+. The number of combined sources. [2]
+. The estimated standard deviation of the combined offset (in seconds).
+ [2.940e-03]
+. The remaining offset correction from the previous update (in seconds,
+ positive means the system clock is slow of UTC). [-2.084e-04]
+. The total of the network path delays to the reference clock to which
+ the local clock is ultimately synchronised (in seconds). [1.534e-02]
+. The total dispersion accumulated through all the servers back to the
+ reference clock to which the local clock is ultimately synchronised
+ (in seconds). [3.472e-04]
+. The maximum estimated error of the system clock in the interval since the
+ previous update (in seconds). It includes the offset, remaining offset
+ correction, root delay, and dispersion from the previous update with the
+ dispersion which accumulated in the interval. [8.304e-03]
++
+*rtc*:::
+This option logs information about the system's real-time clock. An example
+line (which actually appears as a single line in the file) from the _rtc.log_
+file is shown below.
++
+----
+2015-07-22 05:40:50 -0.037360 1 -0.037434\
+ -37.948 12 5 120
+----
++
+The columns are as follows (the quantities in square brackets are the
+values from the example line above):
++
+. Date [2015-07-22]
+. Hour:Minute:Second. Note that the date-time pair is expressed in UTC, not the
+ local time zone. [05:40:50]
+. The measured offset between the RTC and the system clock in seconds.
+ Positive indicates that the RTC is fast of the system time [-0.037360].
+. Flag indicating whether the regression has produced valid coefficients.
+ (1 for yes, 0 for no). [1]
+. Offset at the current time predicted by the regression process. A large
+ difference between this value and the measured offset tends to indicate that
+ the measurement is an outlier with a serious measurement error. [-0.037434]
+. The rate at which the RTC is losing or gaining time relative to the system
+ clock. In ppm, with positive indicating that the RTC is gaining time.
+ [-37.948]
+. The number of measurements used in the regression. [12]
+. The number of runs of regression residuals of the same sign. Low values
+ indicate that a straight line is no longer a good model of the measured data
+ and that older measurements should be discarded. [5]
+. The measurement interval used prior to the measurement being made (in
+ seconds). [120]
++
+*refclocks*:::
+This option logs the raw and filtered reference clock measurements to a file
+called _refclocks.log_. An example line (which actually appears as a single
+line in the file) from the log file is shown below.
++
+----
+2009-11-30 14:33:27.000000 PPS2 7 N 1 4.900000e-07 -6.741777e-07 1.000e-06
+----
++
+The columns are as follows (the quantities in square brackets are the values
+from the example line above):
++
+. Date [2009-11-30]
+. Hour:Minute:Second.Microsecond. Note that the date-time pair is expressed in
+ UTC, not the local time zone. [14:33:27.000000]
+. Reference ID of the reference clock from which the measurement came. [PPS2]
+. Sequence number of driver poll within one polling interval for raw samples,
+ or _-_ for filtered samples. [7]
+. Leap status (_N_ means normal, _+_ means that the last minute of the current
+ month has 61 seconds, _-_ means that the last minute of the month has 59
+ seconds). [N]
+. Flag indicating whether the sample comes from PPS source. (1 for yes,
+ 0 for no, or _-_ for filtered sample). [1]
+. Local clock error measured by reference clock driver, or _-_ for filtered sample.
+ [4.900000e-07]
+. Local clock error with applied corrections. Positive indicates that the local
+ clock is slow. [-6.741777e-07]
+. Assumed dispersion of the sample. [1.000e-06]
++
+*tempcomp*:::
+This option logs the temperature measurements and system rate compensations to
+a file called _tempcomp.log_. An example line (which actually appears as a
+single line in the file) from the log file is shown below.
++
+----
+2015-04-19 10:39:48 2.8000e+04 3.6600e-01
+----
++
+The columns are as follows (the quantities in square brackets are the values
+from the example line above):
++
+. Date [2015-04-19]
+. Hour:Minute:Second. Note that the date-time pair is expressed in UTC, not the
+ local time zone. [10:39:48]
+. Temperature read from the sensor. [2.8000e+04]
+. Applied compensation in ppm, positive means the system clock is running
+ faster than it would be without the compensation. [3.6600e-01]
++
+::
+An example of the directive is:
++
+----
+log measurements statistics tracking
+----
+
+[[logbanner]]*logbanner* _entries_::
+A banner is periodically written to the log files enabled by the <<log,*log*>>
+directive to indicate the meanings of the columns.
++
+The *logbanner* directive specifies after how many entries in the log file
+should be the banner written. The default is 32, and 0 can be used to disable
+it entirely.
+
+[[logchange]]*logchange* _threshold_::
+This directive sets the threshold for the adjustment of the system clock that
+will generate a syslog message. Clock errors detected via NTP packets,
+reference clocks, or timestamps entered via the
+<<chronyc.adoc#settime,*settime*>> command of *chronyc* are logged.
++
+By default, the threshold is 1 second.
++
+An example of the use is:
++
+----
+logchange 0.1
+----
++
+which would cause a syslog message to be generated if a system clock error of over
+0.1 seconds starts to be compensated.
+
+[[logdir]]*logdir* _directory_::
+This directive allows the directory where log files are written to be
+specified.
++
+An example of the use of this directive is:
++
+----
+logdir /var/log/chrony
+----
+
+[[mailonchange]]*mailonchange* _email_ _threshold_::
+This directive defines an email address to which mail should be sent if
+*chronyd* applies a correction exceeding a particular threshold to the system
+clock.
++
+An example of the use of this directive is:
++
+----
+mailonchange root@localhost 0.5
+----
++
+This would send a mail message to root if a change of more than 0.5 seconds
+were applied to the system clock.
++
+This directive cannot be used when a system call filter is enabled by the *-F*
+option as the *chronyd* process will not be allowed to fork and execute the
+sendmail binary.
+
+=== Miscellaneous
+
+[[hwtimestamp]]*hwtimestamp* _interface_ [_option_]...::
+This directive enables hardware timestamping of NTP packets sent to and
+received from the specified network interface. The network interface controller
+(NIC) uses its own clock to accurately timestamp the actual transmissions and
+receptions, avoiding processing and queueing delays in the kernel, network
+driver, and hardware. This can significantly improve the accuracy of the
+timestamps and the measured offset, which is used for synchronisation of the
+system clock. In order to get the best results, both sides receiving and
+sending NTP packets (i.e. server and client, or two peers) need to use HW
+timestamping. If the server or peer supports the interleaved mode, it needs to
+be enabled by the *xleave* option in the <<server,*server*>> or the
+<<peer,*peer*>> directive.
++
+This directive is supported on Linux 3.19 and newer. The NIC must support HW
+timestamping, which can be verified with the *ethtool -T* command. The list of
+capabilities should include _SOF_TIMESTAMPING_RAW_HARDWARE_,
+_SOF_TIMESTAMPING_TX_HARDWARE_, and _SOF_TIMESTAMPING_RX_HARDWARE_. Receive
+filter _HWTSTAMP_FILTER_ALL_, or _HWTSTAMP_FILTER_NTP_ALL_, is necessary for
+timestamping of received packets. Timestamping of packets received from bridged
+and bonded interfaces is supported on Linux 4.13 and newer. When *chronyd* is
+running, no other process (e.g. a PTP daemon) should be working with the NIC
+clock.
++
+If the kernel supports software timestamping, it will be enabled for all
+interfaces. The source of timestamps (i.e. hardware, kernel, or daemon) is
+indicated in the _measurements.log_ file if enabled by the <<log,*log
+measurements*>> directive, and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in
+*chronyc*.
++
+If the specified interface is _*_, *chronyd* will try to enable HW timestamping
+on all available interfaces.
++
+The *hwtimestamp* directive has the following options:
++
+*minpoll* _poll_:::
+This option specifies the minimum interval between readings of the NIC clock.
+It's defined as a power of two. It should correspond to the minimum polling
+interval of all NTP sources and the minimum expected polling interval of NTP
+clients. The default value is 0 (1 second) and the minimum value is -6 (1/64th
+of a second).
+*minsamples* _samples_:::
+This option specifies the minimum number of readings kept for tracking of the
+NIC clock. The default value is 2.
+*maxsamples* _samples_:::
+This option specifies the maximum number of readings kept for tracking of the
+NIC clock. The default value is 16.
+*precision* _precision_:::
+This option specifies the assumed precision of reading of the NIC clock. The
+default value is 100e-9 (100 nanoseconds).
+*txcomp* _compensation_:::
+This option specifies the difference in seconds between the actual transmission
+time at the physical layer and the reported transmit timestamp. This value will
+be added to transmit timestamps obtained from the NIC. The default value is 0.
+*rxcomp* _compensation_:::
+This option specifies the difference in seconds between the reported receive
+timestamp and the actual reception time at the physical layer. This value will
+be subtracted from receive timestamps obtained from the NIC. The default value
+is 0.
+*nocrossts*:::
+Some hardware can precisely cross timestamp the NIC clock with the system
+clock. This option disables the use of the cross timestamping.
+*rxfilter* _filter_:::
+This option selects the receive timestamping filter. The _filter_ can be one of
+the following:
+_all_::::
+Enables timestamping of all received packets.
+_ntp_::::
+Enables timestamping of received NTP packets.
+_none_::::
+Disables timestamping of received packets.
+:::
+The most specific filter for timestamping NTP packets which is supported by the
+NIC is selected by default. Some NICs can timestamp only PTP packets, which
+limits the selection to the _none_ filter. Forcing timestamping of all packets
+with the _all_ filter when the NIC supports both _all_ and _ntp_ filters can be
+useful when packets are received from or on a non-standard UDP port (e.g.
+specified by the *port* directive).
+::
++
+Examples of the directive are:
++
+----
+hwtimestamp eth0
+hwtimestamp eth1 txcomp 300e-9 rxcomp 645e-9
+hwtimestamp *
+----
+
+[[include]]*include* _pattern_::
+The *include* directive includes a configuration file or multiple configuration
+files if a wildcard pattern is specified. This can be useful when maintaining
+configuration on multiple hosts to keep the differences in separate files.
++
+An example of the directive is:
++
+----
+include @SYSCONFDIR@/chrony.d/*.conf
+----
+
+[[keyfile]]*keyfile* _file_::
+This directive is used to specify the location of the file containing ID-key
+pairs for authentication of NTP packets.
++
+The format of the directive is shown in the example below:
++
+----
+keyfile @SYSCONFDIR@/chrony.keys
+----
++
+The argument is simply the name of the file containing the ID-key pairs. The
+format of the file is shown below:
++
+----
+10 tulip
+11 hyacinth
+20 MD5 ASCII:crocus
+25 SHA1 HEX:1dc764e0791b11fa67efc7ecbc4b0d73f68a070c
+ ...
+----
++
+Each line consists of an ID, name of an authentication hash function (optional),
+and a password. The ID can be any unsigned integer in the range 1 through
+2^32-1. The default hash function is *MD5*, which is always supported.
++
+If *chronyd* was built with enabled support for hashing using a crypto library
+(nettle, nss, or libtomcrypt), the following functions are available: *MD5*,
+*SHA1*, *SHA256*, *SHA384*, *SHA512*. Depending on which library and version is
+*chronyd* using, some or all of the following functions may also be available:
+*SHA3-224*, *SHA3-256*, *SHA3-384*, *SHA3-512*, *RMD128*, *RMD160*, *RMD256*,
+*RMD320*, *TIGER*, *WHIRLPOOL*.
++
+The password can be specified as a string of characters not containing white
+space with an optional *ASCII:* prefix, or as a hexadecimal number with the
+*HEX:* prefix. The maximum length of the line is 2047 characters.
++
+The password is used with the hash function to generate and verify a message
+authentication code (MAC) in NTP packets. It is recommended to use SHA1, or
+stronger, hash function with random passwords specified in the hexadecimal
+format that have at least 128 bits. *chronyd* will log a warning to
+syslog on start if a source is specified in the configuration file with a key
+that has password shorter than 80 bits.
++
+The <<chronyc.adoc#keygen,*keygen*>> command of *chronyc* can be used to
+generate random keys for the key file. By default, it generates 160-bit MD5 or
+SHA1 keys.
++
+For security reasons, the file should be readable only by root and the user
+under which *chronyd* is normally running (to allow *chronyd* to re-read the
+file when the <<chronyc.adoc#rekey,*rekey*>> command is issued by *chronyc*).
+
+[[lock_all]]*lock_all*::
+The *lock_all* directive will lock chronyd into RAM so that it will never be
+paged out. This mode is only supported on Linux. This directive uses the Linux
+*mlockall()* system call to prevent *chronyd* from ever being swapped out. This
+should result in lower and more consistent latency. It should not have
+significant impact on performance as *chronyd's* memory usage is modest. The
+*mlockall(2)* man page has more details.
+
+[[pidfile]]*pidfile* _file_::
+Unless *chronyd* is started with the *-Q* option, it writes its process ID
+(PID) to a file, and checks this file on startup to see if another *chronyd*
+might already be running on the system. By default, the file used is
+_@DEFAULT_PID_FILE@_. The *pidfile* directive allows the name to be changed,
+e.g.:
++
+----
+pidfile /run/chronyd.pid
+----
+
+[[sched_priority]]*sched_priority* _priority_::
+On Linux, the *sched_priority* directive will select the SCHED_FIFO real-time
+scheduler at the specified priority (which must be between 0 and 100). On
+macOS, this option must have either a value of 0 (the default) to disable the
+thread time constraint policy or 1 for the policy to be enabled. Other systems
+do not support this option.
++
+On Linux, this directive uses the *sched_setscheduler()* system call to
+instruct the kernel to use the SCHED_FIFO first-in, first-out real-time
+scheduling policy for *chronyd* with the specified priority. This means that
+whenever *chronyd* is ready to run it will run, interrupting whatever else is
+running unless it is a higher priority real-time process. This should not
+impact performance as *chronyd* resource requirements are modest, but it should
+result in lower and more 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(2)* man page has more
+details.
++
+On macOS, this directive uses the *thread_policy_set()* kernel call to
+specify real-time scheduling. As noted for Linux, you should not use this
+directive unless you really need it.
+
+[[user]]*user* _user_::
+The *user* directive sets the name of the system user to which *chronyd* will
+switch after start in order to drop root privileges.
++
+On Linux, *chronyd* needs to be compiled with support for the *libcap* library.
+On macOS, FreeBSD, NetBSD and Solaris *chronyd* forks into two processes.
+The child process retains root privileges, but can only perform a very limited
+range of privileged system calls on behalf of the parent.
++
+The compiled-in default value is _@DEFAULT_USER@_.
+
+[[examples]]
+== EXAMPLES
+
+=== NTP client with permanent connection to NTP servers
+
+This section shows how to configure *chronyd* for computers that are connected
+to the Internet (or to any network containing true NTP servers which ultimately
+derive their time from a reference clock) permanently or most of the time.
+
+To operate in this mode, you will need to know the names of the NTP servers
+you want to use. You might be able to find names of suitable servers by one of
+the following methods:
+
+* Your institution might already operate servers on its network.
+ Contact your system administrator to find out.
+* Your ISP probably has one or more NTP servers available for its
+ customers.
+* Somewhere under the NTP homepage there is a list of public
+ stratum 1 and stratum 2 servers. You should find one or more servers that are
+ near to you. Check that their access policy allows you to use their
+ facilities.
+* Use public servers from the http://www.pool.ntp.org/[pool.ntp.org] project.
+
+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 foo.example.net
+server bar.example.net
+server baz.example.net
+----
+
+However, you will probably want to include some of the other directives. The
+<<driftfile,*driftfile*>>, <<makestep,*makestep*>> and <<rtcsync,*rtcsync*>>
+might be particularly useful. Also, the *iburst* option of the
+<<server,*server*>> directive is useful to speed up the initial
+synchronisation. 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 @CHRONYVARDIR@/drift
+makestep 1.0 3
+rtcsync
+----
+
+When using a pool of NTP servers (one name is used for multiple servers which
+might change over time), it is better to specify them with the <<pool,*pool*>>
+directive instead of multiple *server* directives. The configuration file could
+in this case look like:
+
+----
+pool pool.ntp.org iburst
+driftfile @CHRONYVARDIR@/drift
+makestep 1.0 3
+rtcsync
+----
+
+=== NTP client with infrequent connection to NTP servers
+
+This section shows how to configure *chronyd* for computers that have
+occasional connections to NTP servers. In this case, you will need some
+additional configuration to tell *chronyd* when the connection goes up and
+down. This saves the program from continuously trying to poll the servers when
+they are inaccessible.
+
+Again, assuming that your NTP servers are called _foo.example.net_,
+_bar.example.net_ and _baz.example.net_, your _chrony.conf_ file would now
+contain:
+
+----
+server foo.example.net offline
+server bar.example.net offline
+server baz.example.net offline
+driftfile @CHRONYVARDIR@/drift
+makestep 1.0 3
+rtcsync
+----
+
+The *offline* keyword indicates that the servers start in an offline state, and
+that they should not be contacted until *chronyd* receives notification from
+*chronyc* that the link to the Internet is present. To tell *chronyd* when to
+start and finish sampling the servers, the <<chronyc.adoc#online,*online*>> and
+<<chronyc.adoc#offline,*offline*>> commands of *chronyc* need to be used.
+
+To give an example of their use, assuming that *pppd* is the program being
+used to connect to the Internet and that *chronyc* has been installed at
+_@BINDIR@/chronyc_, the script _/etc/ppp/ip-up_ would include:
+
+----
+@BINDIR@/chronyc online
+----
+
+and the script _/etc/ppp/ip-down_ would include:
+
+----
+@BINDIR@/chronyc offline
+----
+
+*chronyd*'s polling of the servers would now only occur whilst the machine is
+actually connected to the Internet.
+
+=== Isolated networks
+
+This section shows how to configure *chronyd* for computers that never have
+network conectivity to any computer which ultimately derives its time from a
+reference clock.
+
+In this situation, one computer is selected to be the master timeserver. The
+other computers are either direct clients of the master, or clients of clients.
+
+The <<local,*local*>> directive enables a local reference mode, which allows
+*chronyd* to appear synchronised even when it is not.
+
+The rate value in the master's drift file needs to be set to the average rate
+at which the master gains or loses time. *chronyd* includes support for this,
+in the form of the <<manual,*manual*>> directive and the
+<<chronyc.adoc#settime,*settime*>> command in the *chronyc* program.
+
+If the master is rebooted, *chronyd* can re-read the drift rate from the drift
+file. However, the master has no accurate estimate of the current time. To get
+around this, the system can be configured so that the master can initially set
+itself to a '`majority-vote`' of selected clients' times; this allows the
+clients to '`flywheel`' the master while it is rebooting.
+
+The <<smoothtime,*smoothtime*>> directive is useful when the clocks of the
+clients need to stay close together when the local time is adjusted by the
+<<chronyc.adoc#settime,*settime*>> command. The smoothing process needs to be
+activated by the <<chronyc.adoc#smoothtime,*smoothtime activate*>> command when
+the local time is ready to be served. After that point, any adjustments will be
+smoothed out.
+
+A typical configuration file for the master (called _master_) might be
+(assuming the clients and the master are in the _192.168.165.x_ subnet):
+
+----
+initstepslew 1 client1 client3 client6
+driftfile @CHRONYVARDIR@/drift
+local stratum 8
+manual
+allow 192.168.165.0/24
+smoothtime 400 0.01
+rtcsync
+----
+
+For the clients that have to resynchronise the master when it restarts,
+the configuration file might be:
+
+----
+server master iburst
+driftfile @CHRONYVARDIR@/drift
+allow 192.168.165.0/24
+makestep 1.0 3
+rtcsync
+----
+
+The rest of the clients would be the same, except that the *allow* directive is
+not required.
+
+If there is no suitable computer to be designated as the master, or there is a
+requirement to keep the clients synchronised even when it fails, the *orphan*
+option of the *local* directive enables a special mode where the master is
+selected from multiple computers automatically. They all need to use the same
+*local* configuration and poll one another. The server with the smallest
+reference ID (which is based on its IP address) will take the role of the
+master and others will be synchronised to it. When it fails, the server with
+the second smallest reference ID will take over and so on.
+
+A configuration file for the first server might be (assuming there are three
+servers called _master1_, _master2_, and _master3_):
+
+----
+initstepslew 1 master2 master3
+server master2
+server master3
+driftfile @CHRONYVARDIR@/drift
+local stratum 8 orphan
+manual
+allow 192.168.165.0/24
+rtcsync
+----
+
+The other servers would be the same, except the hostnames in the *initstepslew*
+and *server* directives would be modified to specify the other servers. Their
+clients might be configured to poll all three servers.
+
+=== RTC tracking
+
+This section considers a computer which has occasional connections to the
+Internet and is turned off between '`sessions`'. In this case, *chronyd* relies
+on the computer's RTC to maintain the time between the periods when it is
+powered up. It assumes that Linux is run exclusively on the computer. Dual-boot
+systems might work; it depends what (if anything) the other system does to the
+RTC. On 2.6 and later kernels, if your motherboard has a HPET, you will need to
+enable the *HPET_EMULATE_RTC* option in your kernel configuration. Otherwise,
+*chronyd* will not be able to interact with the RTC device and will give up
+using it.
+
+When the computer is connected to the Internet, *chronyd* has access to
+external NTP servers which it makes measurements from. These measurements are
+saved, and straight-line fits are performed on them to provide an estimate of
+the computer's time error and rate of gaining or losing time.
+
+When the computer is taken offline from the Internet, the best estimate of the
+gain or loss rate is used to free-run the computer until it next goes online.
+
+Whilst the computer is running, *chronyd* makes measurements of the RTC (via
+the _/dev/rtc_ interface, which must be compiled into the kernel). An estimate
+is made of the RTC error at a particular RTC second, and the rate at which the
+RTC gains or loses time relative to true time.
+
+When the computer is powered down, the measurement histories for all the NTP
+servers are saved to files, and the RTC tracking information is also
+saved to a file (if the <<rtcfile,*rtcfile*>> directive has been specified).
+These pieces of information are also saved if the <<chronyc.adoc#dump,*dump*>>
+and <<chronyc.adoc#writertc,*writertc*>> commands respectively are issued
+through *chronyc*.
+
+When the computer is rebooted, *chronyd* reads the current RTC time and the RTC
+information saved at the last shutdown. This information is used to set the
+system clock to the best estimate of what its time would have been now, had it
+been left running continuously. The measurement histories for the servers are
+then reloaded.
+
+The next time the computer goes online, the previous sessions' measurements can
+contribute to the line-fitting process, which gives a much better estimate of
+the computer's gain or loss rate.
+
+One problem with saving the measurements and RTC data when the machine is shut
+down is what happens if there is a power failure; the most recent data will not
+be saved. Although *chronyd* is robust enough to cope with this, some
+performance might be lost. (The main danger arises if the RTC has been changed
+during the session, with the *trimrtc* command in *chronyc*. Because of this,
+*trimrtc* will make sure that a meaningful RTC file is saved after the
+change is completed).
+
+The easiest protection against power failure is to put the *dump* and
+*writertc* commands in the same place as the *offline* command is issued to
+take *chronyd* offline; because *chronyd* free-runs between online sessions, no
+parameters will change significantly between going offline from the Internet
+and any power failure.
+
+A final point regards computers which are left running for extended periods and
+where it is desired to spin down the hard disc when it is not in use (e.g. when
+not accessed for 15 minutes). *chronyd* has been planned so it supports such
+operation; this is the reason why the RTC tracking parameters are not saved to
+disc after every update, but only when the user requests such a write, or
+during the shutdown sequence. The only other facility that will generate
+periodic writes to the disc is the *log rtc* facility in the configuration
+file; this option should not be used if you want your disc to spin down.
+
+To illustrate how a computer might be configured for this case, example
+configuration files are shown.
+
+For the _chrony.conf_ file, the following can be used as an example.
+
+----
+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
+makestep 1.0 3
+maxupdateskew 100.0
+dumpdir @CHRONYVARDIR@
+rtcfile @CHRONYVARDIR@/rtc
+----
+
+*pppd* is used for connecting to the Internet. This runs two scripts
+_/etc/ppp/ip-up_ and _/etc/ppp/ip-down_ when the link goes online and offline
+respectively.
+
+The relevant part of the _/etc/ppp/ip-up_ file is:
+
+----
+@BINDIR@/chronyc online
+----
+
+and the relevant part of the _/etc/ppp/ip-down_ script is:
+
+----
+@BINDIR@/chronyc -m offline dump writertc
+----
+
+*chronyd* is started during the boot sequence with the *-r* and *-s* options.
+It might need to be started before any software that depends on the system clock
+not jumping or moving backwards, depending on the directives in *chronyd*'s
+configuration file.
+
+For the system shutdown, *chronyd* should receive a SIGTERM several seconds
+before the final SIGKILL; the SIGTERM causes the measurement histories and RTC
+information to be saved.
+
+=== Public NTP server
+
+*chronyd* can be configured to operate as a public NTP server, e.g. to join the
+http://www.pool.ntp.org/en/join.html[pool.ntp.org] project. The configuration
+is similar to the NTP client with permanent connection, except it needs to
+allow client access from all addresses. It is recommended to find at least four
+good servers (e.g. from the pool, or on the NTP homepage). If the server has a
+hardware reference clock (e.g. a GPS receiver), it can be specified by the
+<<refclock,*refclock*>> directive.
+
+The amount of memory used for logging client accesses can be increased in order
+to enable clients to use the interleaved mode even when the server has a large
+number of clients, and better support rate limiting if it is enabled by the
+<<ratelimit,*ratelimit*>> directive. The system timezone database, if it is
+kept up to date and includes the _right/UTC_ timezone, can be used as a
+reliable source to determine when a leap second will be applied to UTC. The
+*-r* option with the <<dumpdir,*dumpdir*>> directive shortens the time in which
+*chronyd* will not be able to serve time to its clients when it needs to be
+restarted (e.g. after upgrading to a newer version, or a change in the
+configuration).
+
+The configuration file could look like:
+
+----
+server foo.example.net iburst
+server bar.example.net iburst
+server baz.example.net iburst
+server qux.example.net iburst
+makestep 1.0 3
+rtcsync
+allow
+clientloglimit 100000000
+leapsectz right/UTC
+driftfile @CHRONYVARDIR@/drift
+dumpdir @CHRONYRUNDIR@
+----
+
+== SEE ALSO
+
+<<chronyc.adoc#,*chronyc(1)*>>, <<chronyd.adoc#,*chronyd(8)*>>
+
+== BUGS
+
+For instructions on how to report bugs, please visit
+https://chrony.tuxfamily.org/.
+
+== AUTHORS
+
+chrony was written by Richard Curnow, Miroslav Lichvar, and others.
diff --git a/doc/chrony.conf.man.in b/doc/chrony.conf.man.in
new file mode 100644
index 0000000..d50e825
--- /dev/null
+++ b/doc/chrony.conf.man.in
@@ -0,0 +1,3981 @@
+'\" t
+.\" Title: chrony.conf
+.\" Author: [see the "AUTHORS" section]
+.\" Generator: Asciidoctor 1.5.6.1
+.\" Date: 2018-09-19
+.\" Manual: Configuration Files
+.\" Source: chrony @CHRONY_VERSION@
+.\" Language: English
+.\"
+.TH "CHRONY.CONF" "5" "2018-09-19" "chrony @CHRONY_VERSION@" "Configuration Files"
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.ss \n[.ss] 0
+.nh
+.ad l
+.de URL
+\\$2 \(laURL: \\$1 \(ra\\$3
+..
+.if \n[.g] .mso www.tmac
+.LINKSTYLE blue R < >
+.SH "NAME"
+chrony.conf \- chronyd configuration file
+.SH "SYNOPSIS"
+.sp
+\fBchrony.conf\fP
+.SH "DESCRIPTION"
+.sp
+This file configures the \fBchronyd\fP daemon. The compiled\-in location is
+\fI@SYSCONFDIR@/chrony.conf\fP, but other locations can be specified on the
+\fBchronyd\fP command line with the \fB\-f\fP option.
+.sp
+Each directive in the configuration file is placed on a separate line. The
+following sections describe each of the directives in turn. The directives can
+occur in any order in the file and they are not case\-sensitive.
+.sp
+The configuration directives can also be specified directly on the \fBchronyd\fP
+command line. In this case each argument is parsed as a new line and the
+configuration file is ignored.
+.sp
+While the number of supported directives is large, only a few of them are
+typically needed. See the \fBEXAMPLES\fP section for configuration in
+typical operating scenarios.
+.sp
+The configuration file might contain comment lines. A comment line is any line
+that starts with zero or more spaces followed by any one of the following
+characters: \fB!\fP, \fB;\fP, \fB#\fP, \fB%\fP. Any line with this format will be ignored.
+.SH "DIRECTIVES"
+.SS "Time sources"
+.sp
+\fBserver\fP \fIhostname\fP [\fIoption\fP]...
+.RS 4
+The \fBserver\fP directive specifies an NTP server which can be used as a time
+source. The client\-server relationship is strictly hierarchical: a client might
+synchronise its system time to that of the server, but the server\(cqs system time
+will never be influenced by that of a client.
+.sp
+The \fBserver\fP directive is immediately followed by either the name of the
+server, or its IP address. The \fBserver\fP directive supports the following
+options:
+.sp
+\fBminpoll\fP \fIpoll\fP
+.RS 4
+This option specifies the minimum interval between requests sent to the server
+as a power of 2 in seconds. For example, \fBminpoll 5\fP would mean that the
+polling interval should not drop below 32 seconds. The default is 6 (64
+seconds), the minimum is \-6 (1/64th of a second), and the maximum is 24 (6
+months). Note that intervals shorter than 6 (64 seconds) should generally not
+be used with public servers on the Internet, because it might be considered
+abuse. A sub\-second interval will be enabled only when the server is reachable
+and the round\-trip delay is shorter than 10 milliseconds, i.e. the server
+should be in a local network.
+.RE
+.sp
+\fBmaxpoll\fP \fIpoll\fP
+.RS 4
+This option specifies the maximum interval between requests sent to the server
+as a power of 2 in seconds. For example, \fBmaxpoll 9\fP indicates that the polling
+interval should stay at or below 9 (512 seconds). The default is 10 (1024
+seconds), the minimum is \-6 (1/64th of a second), and the maximum is 24 (6
+months).
+.RE
+.sp
+\fBiburst\fP
+.RS 4
+With this option, the interval between the first four requests sent to the
+server will be 2 seconds or less instead of the interval specified by the
+\fBminpoll\fP option, which allows \fBchronyd\fP to make the first update of the clock
+shortly after start.
+.RE
+.sp
+\fBburst\fP
+.RS 4
+With this option, \fBchronyd\fP will shorten the interval between up to four
+requests to 2 seconds or less when it cannot get a good measurement from the
+server. The number of requests in the burst is limited by the current polling
+interval to keep the average interval at or above the minimum interval, i.e.
+the current interval needs to be at least two times longer than the minimum
+interval in order to allow a burst with two requests.
+.RE
+.sp
+\fBkey\fP \fIID\fP
+.RS 4
+The NTP protocol supports a message authentication code (MAC) to prevent
+computers having their system time upset by rogue packets being sent to them.
+The MAC is generated as a function of a password specified in the key file,
+which is specified by the \fBkeyfile\fP directive.
+.sp
+The \fBkey\fP option specifies which key (with an ID in the range 1 through 2^32\-1)
+should \fBchronyd\fP use to authenticate requests sent to the server and verify its
+responses. The server must have the same key for this number configured,
+otherwise no relationship between the computers will be possible.
+.sp
+If the server is running \fBntpd\fP and the output size of the hash function used
+by the key is longer than 160 bits (e.g. SHA256), the \fBversion\fP option needs to
+be set to 4 for compatibility.
+.RE
+.sp
+\fBmaxdelay\fP \fIdelay\fP
+.RS 4
+\fBchronyd\fP uses the network round\-trip delay to the server to determine how
+accurate a particular measurement is likely to be. Long round\-trip delays
+indicate that the request, or the response, or both were delayed. If only one
+of the messages was delayed the measurement error is likely to be substantial.
+.sp
+For small variations in the round\-trip delay, \fBchronyd\fP uses a weighting scheme
+when processing the measurements. However, beyond a certain level of delay the
+measurements are likely to be so corrupted as to be useless. (This is
+particularly so on dial\-up or other slow links, where a long delay probably
+indicates a highly asymmetric delay caused by the response waiting behind a lot
+of packets related to a download of some sort).
+.sp
+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 \fBmaxdelay\fP
+option. For example, \fBmaxdelay 0.3\fP would indicate that measurements with a
+round\-trip delay of 0.3 seconds or more should be ignored. The default value is
+3 seconds and the maximum value is 1000 seconds.
+.RE
+.sp
+\fBmaxdelayratio\fP \fIratio\fP
+.RS 4
+This option is similar to the \fBmaxdelay\fP option above. \fBchronyd\fP keeps a record
+of the minimum round\-trip delay amongst the previous measurements that it has
+buffered. If a measurement has a round trip delay that is greater than the
+maxdelayratio times the minimum delay, it will be rejected.
+.RE
+.sp
+\fBmaxdelaydevratio\fP \fIratio\fP
+.RS 4
+If a measurement has a ratio of the increase in the round\-trip delay from the
+minimum delay amongst the previous measurements to the standard deviation of
+the previous measurements that is greater than the specified ratio, it will be
+rejected. The default is 10.0.
+.RE
+.sp
+\fBmindelay\fP \fIdelay\fP
+.RS 4
+This option specifies a fixed minimum round\-trip delay to be used instead of
+the minimum amongst the previous measurements. This can be useful in networks
+with static configuration to improve the stability of corrections for
+asymmetric jitter, weighting of the measurements, and the \fBmaxdelayratio\fP and
+\fBmaxdelaydevratio\fP tests. The value should be set accurately in order to have a
+positive effect on the synchronisation.
+.RE
+.sp
+\fBasymmetry\fP \fIratio\fP
+.RS 4
+This option specifies the asymmetry of the network jitter on the path to the
+source, which is used to correct the measured offset according to the delay.
+The asymmetry can be between \-0.5 and +0.5. A negative value means the delay of
+packets sent to the source is more variable than the delay of packets sent from
+the source back. By default, \fBchronyd\fP estimates the asymmetry automatically.
+.RE
+.sp
+\fBoffset\fP \fIoffset\fP
+.RS 4
+This option specifies a correction (in seconds) which will be applied to
+offsets measured with this source. It\(cqs particularly useful to compensate for a
+known asymmetry in network delay or timestamping errors. For example, if
+packets sent to the source were on average delayed by 100 microseconds more
+than packets sent from the source back, the correction would be \-0.00005 (\-50
+microseconds). The default is 0.0.
+.RE
+.sp
+\fBminsamples\fP \fIsamples\fP
+.RS 4
+Set the minimum number of samples kept for this source. This overrides the
+\fBminsamples\fP directive.
+.RE
+.sp
+\fBmaxsamples\fP \fIsamples\fP
+.RS 4
+Set the maximum number of samples kept for this source. This overrides the
+\fBmaxsamples\fP directive.
+.RE
+.sp
+\fBfilter\fP \fIsamples\fP
+.RS 4
+This option enables a median filter to reduce noise in NTP measurements. The
+filter will reduce the specified number of samples to a single sample. It is
+intended to be used with very short polling intervals in local networks where
+it is acceptable to generate a lot of NTP traffic.
+.RE
+.sp
+\fBoffline\fP
+.RS 4
+If the server will not be reachable when \fBchronyd\fP is started, the \fBoffline\fP
+option can be specified. \fBchronyd\fP will not try to poll the server until it is
+enabled to do so (by using the \fBonline\fP command in
+\fBchronyc\fP).
+.RE
+.sp
+\fBauto_offline\fP
+.RS 4
+With this option, the server will be assumed to have gone offline when sending
+a request fails, e.g. due to a missing route to the network. This option avoids
+the need to run the \fBoffline\fP command from \fBchronyc\fP
+when disconnecting the network link. (It will still be necessary to use the
+\fBonline\fP command when the link has been established, to
+enable measurements to start.)
+.RE
+.sp
+\fBprefer\fP
+.RS 4
+Prefer this source over sources without the \fBprefer\fP option.
+.RE
+.sp
+\fBnoselect\fP
+.RS 4
+Never select this source. This is particularly useful for monitoring.
+.RE
+.sp
+\fBtrust\fP
+.RS 4
+Assume time from this source is always true. It can be rejected as a
+falseticker in the source selection only if another source with this option
+does not agree with it.
+.RE
+.sp
+\fBrequire\fP
+.RS 4
+Require that at least one of the sources specified with this option is
+selectable (i.e. recently reachable and not a falseticker) before updating the
+clock. Together with the \fBtrust\fP option this might be useful to allow a trusted
+authenticated source to be safely combined with unauthenticated sources in
+order to improve the accuracy of the clock. They can be selected and used for
+synchronisation only if they agree with the trusted and required source.
+.RE
+.sp
+\fBxleave\fP
+.RS 4
+This option enables an interleaved mode which allows the server or the peer to
+send transmit timestamps captured after the actual transmission (e.g. when the
+server or the peer is running \fBchronyd\fP with software (kernel) or hardware
+timestamping). This can significantly improve the accuracy of the measurements.
+.sp
+The interleaved mode is compatible with servers that support only the basic
+mode, but peers must both support and have enabled the interleaved mode,
+otherwise the synchronisation will work only in one direction. Note that even
+servers that support the interleaved mode might respond in the basic mode as
+the interleaved mode requires the servers to keep some state for each client
+and the state might be dropped when there are too many clients (e.g.
+\fBclientloglimit\fP is too small), or it might be overwritten
+by other clients that have the same IP address (e.g. computers behind NAT or
+someone sending requests with a spoofed source address).
+.sp
+The \fBxleave\fP option can be combined with the \fBpresend\fP option in order to
+shorten the interval in which the server has to keep the state to be able to
+respond in the interleaved mode.
+.RE
+.sp
+\fBpolltarget\fP \fItarget\fP
+.RS 4
+Target number of measurements to use for the regression algorithm which
+\fBchronyd\fP will try to maintain by adjusting the polling interval between
+\fBminpoll\fP and \fBmaxpoll\fP. A higher target makes \fBchronyd\fP prefer shorter polling
+intervals. The default is 8 and a useful range is from 6 to 60.
+.RE
+.sp
+\fBport\fP \fIport\fP
+.RS 4
+This option allows the UDP port on which the server understands NTP requests to
+be specified. For normal servers this option should not be required (the
+default is 123, the standard NTP port).
+.RE
+.sp
+\fBpresend\fP \fIpoll\fP
+.RS 4
+If the timing measurements being made by \fBchronyd\fP are the only network data
+passing between two computers, you might find that some measurements are badly
+skewed due to either the client or the server having to do an ARP lookup on the
+other party prior to transmitting a packet. This is more of a problem with long
+sampling intervals, which might be similar in duration to the lifetime of entries
+in the ARP caches of the machines.
+.sp
+In order to avoid this problem, the \fBpresend\fP option can be used. It takes a
+single integer argument, which is the smallest polling interval for which an
+extra pair of NTP packets will be exchanged between the client and the server
+prior to the actual measurement. For example, with the following option
+included in a \fBserver\fP directive:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+presend 9
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+when the polling interval is 512 seconds or more, an extra NTP client packet
+will be sent to the server a short time (2 seconds) before making the actual
+measurement.
+.sp
+The \fBpresend\fP option cannot be used in the \fBpeer\fP directive. If it is used
+with the \fBxleave\fP option, \fBchronyd\fP will send two extra packets instead of one.
+.RE
+.sp
+\fBminstratum\fP \fIstratum\fP
+.RS 4
+When the synchronisation source is selected from available sources, sources
+with lower stratum are normally slightly preferred. This option can be used to
+increase stratum of the source to the specified minimum, so \fBchronyd\fP will
+avoid selecting that source. This is useful with low stratum sources that are
+known to be unreliable or inaccurate and which should be used only when other
+sources are unreachable.
+.RE
+.sp
+\fBversion\fP \fIversion\fP
+.RS 4
+This option sets the NTP version of packets sent to the server. This can be
+useful when the server runs an old NTP implementation that does not respond to
+requests using a newer version. The default version depends on whether a key is
+specified by the \fBkey\fP option and which authentication hash function the key
+is using. If the output size of the hash function is longer than 160 bits, the
+default version is 3 for compatibility with older \fBchronyd\fP servers. Otherwise,
+the default version is 4.
+.RE
+.RE
+.sp
+\fBpool\fP \fIname\fP [\fIoption\fP]...
+.RS 4
+The syntax of this directive is similar to that for the \fBserver\fP
+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 might change over time.
+.sp
+All options valid in the \fBserver\fP directive can be used in this
+directive too. There is one option specific to the \fBpool\fP directive:
+\fBmaxsources\fP sets the maximum number of sources that can be used from the pool,
+the default value is 4.
+.sp
+On start, when the pool name is resolved, \fBchronyd\fP 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 the number specified by the \fBmaxsources\fP
+option, the other sources will be removed. When a pool source is unreachable,
+marked as a falseticker, or has a distance larger than the limit set by the
+\fBmaxdistance\fP directive, \fBchronyd\fP will try to replace the
+source with a newly resolved address from the pool.
+.sp
+An example of the \fBpool\fP directive is
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+pool pool.ntp.org iburst maxsources 3
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBpeer\fP \fIhostname\fP [\fIoption\fP]...
+.RS 4
+The syntax of this directive is identical to that for the \fBserver\fP
+directive, except that it specifies a symmetric association with an NTP peer
+instead of a client/server association with an NTP server. A single symmetric
+association allows the peers to be both servers and clients to each other. This
+is mainly useful when the NTP implementation of the peer (e.g. \fBntpd\fP) supports
+ephemeral symmetric associations and does not need to be configured with an
+address of this host. \fBchronyd\fP does not support ephemeral associations.
+.sp
+When a key is specified by the \fBkey\fP option to enable authentication, both
+peers must use the same key and the same key number.
+.sp
+Note that the symmetric mode is less secure than the client/server mode. A
+denial\-of\-service attack is possible on unauthenticated symmetric associations,
+i.e. when the peer was specified without the \fBkey\fP option. An attacker who does
+not see network traffic between two hosts, but knows that they are peering with
+each other, can periodically send them unauthenticated packets with spoofed
+source addresses in order to disrupt their NTP state and prevent them from
+synchronising to each other. When the association is authenticated, an attacker
+who does see the network traffic, but cannot prevent the packets from reaching
+the other host, can still disrupt the state by replaying old packets. The
+attacker has effectively the same power as a man\-in\-the\-middle attacker. A
+partial protection against this attack is implemented in \fBchronyd\fP, which can
+protect the peers if they are using the same polling interval and they never
+sent an authenticated packet with a timestamp from future, but it should not be
+relied on as it is difficult to ensure the conditions are met. If two hosts
+should be able to synchronise to each other in both directions, it is
+recommended to use two separate client/server associations (specified by the
+\fBserver\fP directive on both hosts) instead.
+.RE
+.sp
+\fBinitstepslew\fP \fIstep\-threshold\fP [\fIhostname\fP]...
+.RS 4
+In normal operation, \fBchronyd\fP slews the time when it needs to adjust the
+system clock. For example, to correct a system clock which is 1 second slow,
+\fBchronyd\fP slightly increases the amount by which the system clock is advanced
+on each clock interrupt, until the error is removed. Note that at no time does
+time run backwards with this method.
+.sp
+On most Unix systems it is not desirable to step the system clock, because many
+programs rely on time advancing monotonically forwards.
+.sp
+When the \fBchronyd\fP daemon is initially started, it is possible that the system
+clock is considerably in error. Attempting to correct such an error by slewing
+might not be sensible, since it might take several hours to correct the error by
+this means.
+.sp
+The purpose of the \fBinitstepslew\fP directive is to allow \fBchronyd\fP to make a
+rapid measurement of the system clock error at boot time, and to correct the