Initial commit for mirror of chrony version 3.3
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..9bd8eaa
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,42 @@
+# chrony NTP daemon
+#
+# From the chrony website (https://chrony.tuxfamily.org/):
+#
+# 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.
+
+licenses(["restricted"])
+
+chrony_version_dir = "chrony_3_3"
+
+package_group(
+    name = "internal",
+    packages = [
+        "//third_party/chrony",
+        "//third_party/chrony/" + chrony_version_dir,
+    ],
+)
+
+package(default_visibility = ["//third_party/chrony:internal"])
+
+exports_files(["LICENSE"])
+
+genrule(
+    name = "chrony_daemon",
+    srcs = ["//third_party/chrony/" + chrony_version_dir + ":chronyd"],
+    outs = ["chronyd"],
+    cmd = "cp $< $@",
+    visibility = ["//visibility:public"],
+)
+
+genrule(
+    name = "chrony_client",
+    srcs = ["//third_party/chrony/" + chrony_version_dir + ":chronyc"],
+    outs = ["chronyc"],
+    cmd = "cp $< $@",
+    visibility = ["//visibility:public"],
+)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/LICENSE
@@ -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/README.md b/README.md
new file mode 100644
index 0000000..a62f60f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,35 @@
+# Package `//third_party/chrony`
+
+google3/third_party/chrony
+
+<!--*
+# Document freshness: For more information, see go/fresh-source.
+freshness: { owner: 'croelle' reviewed: '2020-12-30' }
+*-->
+
+[TOC]
+
+## Overview
+
+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.
+
+See the external project site for more info: https://chrony.tuxfamily.org
+
+## Maintainers
+
+This package is maintained by those listed in the [OWNERS](OWNERS) file, which
+currently comprises only the
+[chrony-owners](http://ganpati2/group/chrony-owners.prod)
+group.  Since third_party OWNERS files require at least two FTEs (see
+go/thirdpartyowners), we cannot use just the MDB group to specify owners, so
+please keep the OWNERS file and the MDB group in sync.
+
+## Users
+
+Anyone who uses chrony should consider joining the
+[chrony-users](http://groups/chrony-users) group, to stay apprised of updates,
+changes, etc.
diff --git a/chrony_3_3/BUILD b/chrony_3_3/BUILD
new file mode 100644
index 0000000..c309720
--- /dev/null
+++ b/chrony_3_3/BUILD
@@ -0,0 +1,104 @@
+# chrony NTP daemon
+#
+# From the chrony website (https://chrony.tuxfamily.org/):
+#
+# 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.
+
+# config.h created with ./configure --without-readline \
+# --without-editline --without-libcap --without-nss
+
+licenses(["restricted"])  # GPLv2
+
+package(default_visibility = ["//third_party/chrony:internal"])
+
+cc_library(
+    name = "chrony_headers",
+    textual_hdrs = glob(["*.h"]) + ["md5.c"],
+)
+
+cc_binary(
+    name = "chronyd",
+    srcs = [
+        "addrfilt.c",
+        "array.c",
+        "clientlog.c",
+        "cmdmon.c",
+        "cmdparse.c",
+        "conf.c",
+        "hash_intmd5.c",
+        "hwclock.c",
+        "keys.c",
+        "local.c",
+        "logging.c",
+        "main.c",
+        "manual.c",
+        "memory.c",
+        "nameserv.c",
+        "nameserv_async.c",
+        "ntp_core.c",
+        "ntp_io.c",
+        "ntp_io_linux.c",
+        "ntp_sources.c",
+        "pktlength.c",
+        "refclock.c",
+        "refclock_phc.c",
+        "refclock_pps.c",
+        "refclock_shm.c",
+        "refclock_sock.c",
+        "reference.c",
+        "regress.c",
+        "rtc.c",
+        "rtc_linux.c",
+        "sched.c",
+        "smooth.c",
+        "sources.c",
+        "sourcestats.c",
+        "stubs.c",
+        "sys.c",
+        "sys_generic.c",
+        "sys_linux.c",
+        "sys_null.c",
+        "sys_timex.c",
+        "tempcomp.c",
+        "util.c",
+    ],
+    copts = [
+        # all instances are of the form
+        # default: assert(0)
+        "-Wno-error",
+    ],
+    defines = select({
+        "//tools/cc_target_os:loonix": [],
+        "//conditions:default": ["HAVE_LONG_TIME_T"],
+    }),
+    deps = [
+        ":chrony_headers",
+    ],
+)
+
+cc_binary(
+    name = "chronyc",
+    srcs = [
+        "array.c",
+        "client.c",
+        "cmdparse.c",
+        "getdate.c",
+        "hash_intmd5.c",
+        "memory.c",
+        "nameserv.c",
+        "pktlength.c",
+        "util.c",
+    ],
+    defines = select({
+        "//tools/cc_target_os:loonix": [],
+        "//conditions:default": ["HAVE_LONG_TIME_T"],
+    }),
+    deps = [
+        ":chrony_headers",
+    ],
+)
diff --git a/chrony_3_3/COPYING b/chrony_3_3/COPYING
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/FAQ b/chrony_3_3/FAQ
new file mode 100644
index 0000000..e8edbf7
--- /dev/null
+++ b/chrony_3_3/FAQ
@@ -0,0 +1,460 @@
+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. 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?
+  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).
+
+An example of the directive for an NTP server on the Internet that you are
+allowed to poll frequently could be
+
+server foo.example.net minpoll 4 maxpoll 6 polltarget 16
+
+An example using very short polling intervals for a server located in the same
+LAN could be
+
+server ntp.local minpoll 2 maxpoll 4 polltarget 30
+
+The maxdelay options are useful to ignore measurements with larger delay (e.g.
+due to congestion in the network) and improve the stability of the
+synchronisation. The maxdelaydevratio option could be added to the example with
+local NTP server
+
+server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
+
+If your server supports the interleaved mode, the xleave option should be added
+to the server directive in order to allow the server to send the client more
+accurate hardware or kernel transmit timestamps. When combined with local
+hardware timestamping, sub-microsecond accuracy may be possible. An example
+could be
+
+server ntp.local minpoll 2 maxpoll 2 xleave
+hwtimestamp eth0
+
+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. 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
+
+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-04-04 09:18:44 CEST
diff --git a/chrony_3_3/INSTALL b/chrony_3_3/INSTALL
new file mode 100644
index 0000000..ebaf9d3
--- /dev/null
+++ b/chrony_3_3/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-04-04 09:18:44 CEST
diff --git a/chrony_3_3/Makefile b/chrony_3_3/Makefile
new file mode 100644
index 0000000..c820b77
--- /dev/null
+++ b/chrony_3_3/Makefile
@@ -0,0 +1,132 @@
+##################################################
+#
+# 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=/etc
+BINDIR=/usr/local/bin
+SBINDIR=/usr/local/sbin
+LOCALSTATEDIR=/var
+CHRONYVARDIR=/var/lib/chrony
+
+CC = gcc
+CFLAGS = -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread
+CPPFLAGS = 
+
+DESTDIR=
+
+HASH_OBJ = hash_intmd5.o
+
+OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o \
+       reference.o regress.o rtc.o sched.o sources.o sourcestats.o stubs.o \
+       smooth.o sys.o sys_null.o tempcomp.o util.o $(HASH_OBJ)
+
+EXTRA_OBJS=sys_generic.o sys_linux.o sys_timex.o cmdmon.o manual.o pktlength.o ntp_core.o ntp_io.o ntp_sources.o addrfilt.o clientlog.o keys.o nameserv.o refclock.o refclock_phc.o refclock_pps.o refclock_shm.o refclock_sock.o nameserv_async.o hwclock.o ntp_io_linux.o rtc_linux.o
+
+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 =  -pie -Wl,-z,relro,-z,now
+LIBS = -lm
+
+EXTRA_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 -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
+
+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/chrony_3_3/Makefile.in b/chrony_3_3/Makefile.in
new file mode 100644
index 0000000..5a4aeee
--- /dev/null
+++ b/chrony_3_3/Makefile.in
@@ -0,0 +1,132 @@
+##################################################
+#
+# 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 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 -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
+
+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/chrony_3_3/NEWS b/chrony_3_3/NEWS
new file mode 100644
index 0000000..bfbb4ce
--- /dev/null
+++ b/chrony_3_3/NEWS
@@ -0,0 +1,811 @@
+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/chrony_3_3/README b/chrony_3_3/README
new file mode 100644
index 0000000..aad727e
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/addressing.h b/chrony_3_3/addressing.h
new file mode 100644
index 0000000..9ecc18b
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/addrfilt.c b/chrony_3_3/addrfilt.c
new file mode 100644
index 0000000..dd16700
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/addrfilt.h b/chrony_3_3/addrfilt.h
new file mode 100644
index 0000000..b8c131f
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/array.c b/chrony_3_3/array.c
new file mode 100644
index 0000000..d70cff9
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/array.h b/chrony_3_3/array.h
new file mode 100644
index 0000000..c812e84
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/candm.h b/chrony_3_3/candm.h
new file mode 100644
index 0000000..6ffbb39
--- /dev/null
+++ b/chrony_3_3/candm.h
@@ -0,0 +1,724 @@
+/*
+  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 N_REQUEST_TYPES 63
+
+/* 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;
+  uint32_t reserved[4];
+  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/chrony_3_3/client.c b/chrony_3_3/client.c
new file mode 100644
index 0000000..3c605c1
--- /dev/null
+++ b/chrony_3_3/client.c
@@ -0,0 +1,3237 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Lonnie Abelbeck  2016
+ * 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 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.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));
+      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"
+    "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
+static char *
+command_name_generator(const char *text, int state)
+{
+  const char *name, *names[] = {
+    "accheck", "activity", "add peer", "add server", "allow", "burst",
+    "clients", "cmdaccheck", "cmdallow", "cmddeny", "cyclelogs", "delete",
+    "deny", "dns", "dump", "exit", "help", "keygen", "local", "makestep",
+    "manual on", "manual off", "manual delete", "manual list", "manual reset",
+    "maxdelay", "maxdelaydevratio", "maxdelayratio", "maxpoll",
+    "maxupdateskew", "minpoll", "minstratum", "ntpdata", "offline", "online",
+    "polltarget", "quit", "refresh", "rekey", "reselect", "reselectdist",
+    "retries", "rtcdata", "serverstats", "settime", "shutdown", "smoothing",
+    "smoothtime", "sources", "sources -v", "sourcestats", "sourcestats -v",
+    "timeout", "tracking", "trimrtc", "waitsync", "writertc",
+    NULL
+  };
+  static int list_index, len;
+
+  if (!state) {
+    list_index = 0;
+    len = strlen(text);
+  }
+
+  while ((name = names[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)
+{
+  rl_attempted_completion_over = 1;
+  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("%4ld", s);
+  } else if (s < 36000) {
+    printf("%3ldm", s / 60);
+  } else if (s < 345600) {
+    printf("%3ldh", s / 3600);
+  } else {
+    d = s / 86400;
+    if (d > 999) {
+      printf("%3ldy", d / 365);
+    } else {
+      printf("%3ldd", 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 %d", &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, "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);
+
+  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/chrony_3_3/clientlog.c b/chrony_3_3/clientlog.c
new file mode 100644
index 0000000..86962a7
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/clientlog.h b/chrony_3_3/clientlog.h
new file mode 100644
index 0000000..552c767
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/cmdmon.c b/chrony_3_3/cmdmon.c
new file mode 100644
index 0000000..3bd8d91
--- /dev/null
+++ b/chrony_3_3/cmdmon.c
@@ -0,0 +1,1705 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2009-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  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 */
+};
+
+/* ================================================== */
+
+/* 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_TakeSourcesOnline(&mask, &address))
+    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_TakeSourcesOffline(&mask, &address))
+    tx_message->status = htons(STT_NOSUCHSOURCE);
+}
+
+/* ================================================== */
+
+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.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.online  = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ? 1 : 0;
+  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;
+
+        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/chrony_3_3/cmdmon.h b/chrony_3_3/cmdmon.h
new file mode 100644
index 0000000..5b717d2
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/cmdparse.c b/chrony_3_3/cmdparse.c
new file mode 100644
index 0000000..a228530
--- /dev/null
+++ b/chrony_3_3/cmdparse.c
@@ -0,0 +1,285 @@
+/*
+  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.online = 1;
+  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.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.online = 0;
+    } 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, "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/chrony_3_3/cmdparse.h b/chrony_3_3/cmdparse.h
new file mode 100644
index 0000000..19f4bb7
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/conf.c b/chrony_3_3/conf.c
new file mode 100644
index 0000000..3859d74
--- /dev/null
+++ b/chrony_3_3/conf.c
@@ -0,0 +1,2028 @@
+/*
+  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->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, "minpoll")) {
+      if (sscanf(line, "%d%n", &iface->minpoll, &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.online = 0;
+
+    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/chrony_3_3/conf.h b/chrony_3_3/conf.h
new file mode 100644
index 0000000..25c98e1
--- /dev/null
+++ b/chrony_3_3/conf.h
@@ -0,0 +1,140 @@
+/*
+  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 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/chrony_3_3/config.h b/chrony_3_3/config.h
new file mode 100644
index 0000000..863d3b5
--- /dev/null
+++ b/chrony_3_3/config.h
@@ -0,0 +1,38 @@
+#define LINUX 1
+#define DEBUG 0
+#define FEAT_CMDMON 1
+#define FEAT_NTP 1
+#define FEAT_REFCLOCK 1
+// HAVE_LONG_TIME_T is now a build-time option (see BUILD)
+//efine HAVE_LONG_TIME_T 1
+#define NTP_ERA_SPLIT (1522971079LL - 18250 * 24 * 3600)
+#define HAVE_STDINT_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_IN_PKTINFO 1
+#define FEAT_IPV6 1
+#define _GNU_SOURCE 1
+#define HAVE_IN6_PKTINFO 1
+#define HAVE_CLOCK_GETTIME 1
+#define HAVE_GETADDRINFO 1
+#define FEAT_ASYNCDNS 1
+#define USE_PTHREAD_ASYNCDNS 1
+#define HAVE_RECVMMSG 1
+#define HAVE_LINUX_TIMESTAMPING 1
+#define HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP 1
+#define HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO 1
+#define HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW 1
+#define FEAT_RTC 1
+#define FEAT_PHC 1
+#define HAVE_SCHED_SETSCHEDULER 1
+#define HAVE_MLOCKALL 1
+#define FORCE_DNSRETRY 1
+#define DEFAULT_CONF_FILE "/etc/chrony.conf"
+#define DEFAULT_HWCLOCK_FILE ""
+#define DEFAULT_PID_FILE "/var/run/chronyd.pid"
+#define DEFAULT_RTC_DEVICE "/dev/rtc"
+#define DEFAULT_USER "root"
+#define DEFAULT_COMMAND_SOCKET "/var/run/chrony/chronyd.sock"
+#define MAIL_PROGRAM "/usr/lib/sendmail"
+#define CHRONYC_FEATURES "-READLINE -SECHASH +IPV6 -DEBUG"
+#define CHRONYD_FEATURES "+CMDMON +NTP +REFCLOCK +RTC -PRIVDROP -SCFILTER -SIGND +ASYNCDNS -SECHASH +IPV6 -DEBUG"
+#define CHRONY_VERSION "3.3"
diff --git a/chrony_3_3/config.log b/chrony_3_3/config.log
new file mode 100644
index 0000000..22380e4
--- /dev/null
+++ b/chrony_3_3/config.log
@@ -0,0 +1,303 @@
+docheck.c:
+#include "config.h"
+int main(int argc, char **argv) {
+
+return 0; }
+gcc -o docheck docheck.c
+
+docheck.c:
+#include "config.h"
+int main(int argc, char **argv) {
+
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+int main(int argc, char **argv) {
+
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <time.h>
+int main(int argc, char **argv) {
+
+  char x[sizeof(time_t) > 4 ? 1 : -1] = {0};
+  return x[0];
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <math.h>
+int main(int argc, char **argv) {
+return (int) pow(2.0, log(sqrt((double)argc)));
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+/tmp/ccDkvCtP.o: In function `main':
+/google/src/cloud/ctalbott/chrony/google3/third_party/chrony/chrony-3.3/docheck.c:4: undefined reference to `log'
+/google/src/cloud/ctalbott/chrony/google3/third_party/chrony/chrony-3.3/docheck.c:4: undefined reference to `pow'
+/google/src/cloud/ctalbott/chrony/google3/third_party/chrony/chrony-3.3/docheck.c:4: undefined reference to `sqrt'
+collect2: error: ld returned 1 exit status
+
+docheck.c:
+#include "config.h"
+#include <math.h>
+int main(int argc, char **argv) {
+return (int) pow(2.0, log(sqrt((double)argc)));
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -o docheck docheck.c -lm -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <stdint.h>
+int main(int argc, char **argv) {
+
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <inttypes.h>
+int main(int argc, char **argv) {
+
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <sys/socket.h>
+#include <netinet/in.h>
+int main(int argc, char **argv) {
+
+  struct in_pktinfo ipi;
+  return sizeof (ipi.ipi_spec_dst.s_addr) + IP_PKTINFO;
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+int main(int argc, char **argv) {
+
+    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));
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <sys/socket.h>
+#include <netinet/in.h>
+int main(int argc, char **argv) {
+
+    return sizeof (struct in6_pktinfo) + IPV6_PKTINFO;
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+docheck.c: In function 'main':
+docheck.c:6:20: error: invalid application of 'sizeof' to incomplete type 'struct in6_pktinfo'
+     return sizeof (struct in6_pktinfo) + IPV6_PKTINFO;
+                    ^~~~~~
+
+docheck.c:
+#include "config.h"
+#include <sys/socket.h>
+#include <netinet/in.h>
+int main(int argc, char **argv) {
+return sizeof (struct in6_pktinfo) + IPV6_PKTINFO;
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -D_GNU_SOURCE -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <time.h>
+int main(int argc, char **argv) {
+clock_gettime(CLOCK_REALTIME, NULL);
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+int main(int argc, char **argv) {
+return getaddrinfo(0, 0, 0, 0);
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <pthread.h>
+int main(int argc, char **argv) {
+return pthread_create((void *)1, NULL, (void *)1, NULL);
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <stdlib.h>
+int main(int argc, char **argv) {
+arc4random_buf(NULL, 0);
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+docheck.c: In function 'main':
+docheck.c:4:1: warning: implicit declaration of function 'arc4random_buf'; did you mean 'srandom_r'? [-Wimplicit-function-declaration]
+ arc4random_buf(NULL, 0);
+ ^~~~~~~~~~~~~~
+ srandom_r
+/tmp/ccgWPyl2.o: In function `main':
+/google/src/cloud/ctalbott/chrony/google3/third_party/chrony/chrony-3.3/docheck.c:4: undefined reference to `arc4random_buf'
+collect2: error: ld returned 1 exit status
+
+docheck.c:
+#include "config.h"
+#include <stdlib.h>
+#include <sys/random.h>
+int main(int argc, char **argv) {
+return getrandom(NULL, 256, 0);
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+docheck.c:3:10: fatal error: sys/random.h: No such file or directory
+ #include <sys/random.h>
+          ^~~~~~~~~~~~~~
+compilation terminated.
+
+docheck.c:
+#include "config.h"
+#include <sys/socket.h>
+int main(int argc, char **argv) {
+
+  struct mmsghdr hdr;
+  return !recvmmsg(0, &hdr, 1, MSG_DONTWAIT, 0);
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/net_tstamp.h>
+#include <linux/errqueue.h>
+#include <linux/ptp_clock.h>
+int main(int argc, char **argv) {
+
+    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));
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/net_tstamp.h>
+int main(int argc, char **argv) {
+
+    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;
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <sys/timepps.h>
+int main(int argc, char **argv) {
+
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+docheck.c:2:10: fatal error: sys/timepps.h: No such file or directory
+ #include <sys/timepps.h>
+          ^~~~~~~~~~~~~~~
+compilation terminated.
+
+docheck.c:
+#include "config.h"
+#include <timepps.h>
+int main(int argc, char **argv) {
+
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+docheck.c:2:10: fatal error: timepps.h: No such file or directory
+ #include <timepps.h>
+          ^~~~~~~~~~~
+compilation terminated.
+
+docheck.c:
+#include "config.h"
+#include <sys/ioctl.h>
+#include <linux/rtc.h>
+int main(int argc, char **argv) {
+ioctl(1, RTC_UIE_ON&RTC_UIE_OFF&RTC_RD_TIME&RTC_SET_TIME, 0&RTC_UF);
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <sys/ioctl.h>
+#include <linux/ptp_clock.h>
+int main(int argc, char **argv) {
+ioctl(1, PTP_CLOCK_GETCAPS + PTP_SYS_OFFSET, 0);
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <sched.h>
+int main(int argc, char **argv) {
+
+     struct sched_param sched;
+     sched_get_priority_max(SCHED_FIFO);
+     sched_setscheduler(0, SCHED_FIFO, &sched);
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <sys/mman.h>
+#include <sys/resource.h>
+int main(int argc, char **argv) {
+
+     struct rlimit rlim;
+     setrlimit(RLIMIT_MEMLOCK, &rlim);
+     mlockall(MCL_CURRENT|MCL_FUTURE);
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+
+docheck.c:
+#include "config.h"
+#include <nettle/nettle-meta.h>
+#include <nettle/sha2.h>
+int main(int argc, char **argv) {
+return nettle_hashes[0]->context_size;
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -o docheck docheck.c -pie -Wl,-z,relro,-z,now
+docheck.c:2:10: fatal error: nettle/nettle-meta.h: No such file or directory
+ #include <nettle/nettle-meta.h>
+          ^~~~~~~~~~~~~~~~~~~~~~
+compilation terminated.
+
+docheck.c:
+#include "config.h"
+#include <tomcrypt.h>
+int main(int argc, char **argv) {
+hash_memory_multi(find_hash("md5"), NULL, NULL, NULL, 0, NULL, 0);
+return 0; }
+gcc -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread -I/usr/include/tomcrypt -o docheck docheck.c -ltomcrypt -pie -Wl,-z,relro,-z,now
+docheck.c:2:10: fatal error: tomcrypt.h: No such file or directory
+ #include <tomcrypt.h>
+          ^~~~~~~~~~~~
+compilation terminated.
+
diff --git a/chrony_3_3/configure b/chrony_3_3/configure
new file mode 100755
index 0000000..25773de
--- /dev/null
+++ b/chrony_3_3/configure
@@ -0,0 +1,1015 @@
+#!/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/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/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 '<stdint.h>' 'stdint.h' '' '' ''; then
+  add_def HAVE_STDINT_H
+fi
+
+if test_code '<inttypes.h>' 'inttypes.h' '' '' ''; then
+  add_def HAVE_INTTYPES_H
+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 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>' 'sys/timepps.h' '' '' ''; then
+    timepps_h="sys/timepps.h"
+    add_def HAVE_SYS_TIMEPPS_H
+  else
+    if test_code '<timepps.h>' 'timepps.h' '' '' ''; then
+      timepps_h="timepps.h"
+      add_def HAVE_TIMEPPS_H
+    fi
+  fi
+fi
+
+if [ "x$timepps_h" != "x" ] && \
+  test_code 'PPSAPI' "string.h $timepps_h" '' '' '
+    pps_handle_t h = 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/chrony_3_3/contrib/andrew_bishop_1 b/chrony_3_3/contrib/andrew_bishop_1
new file mode 100644
index 0000000..4c0b437
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/contrib/andrew_bishop_2 b/chrony_3_3/contrib/andrew_bishop_2
new file mode 100644
index 0000000..d3ede74
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/contrib/bryan_christianson_1/README.txt b/chrony_3_3/contrib/bryan_christianson_1/README.txt
new file mode 100644
index 0000000..3a0a2ef
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/contrib/bryan_christianson_1/chronylogrotate.sh b/chrony_3_3/contrib/bryan_christianson_1/chronylogrotate.sh
new file mode 100755
index 0000000..f919544
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/contrib/bryan_christianson_1/org.tuxfamily.chronyc.plist b/chrony_3_3/contrib/bryan_christianson_1/org.tuxfamily.chronyc.plist
new file mode 100644
index 0000000..a3c42c6
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/contrib/bryan_christianson_1/org.tuxfamily.chronyd.plist b/chrony_3_3/contrib/bryan_christianson_1/org.tuxfamily.chronyd.plist
new file mode 100644
index 0000000..2bf42aa
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/contrib/erik_bryer_1 b/chrony_3_3/contrib/erik_bryer_1
new file mode 100644
index 0000000..c551dfe
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/contrib/ken_gillett_1 b/chrony_3_3/contrib/ken_gillett_1
new file mode 100644
index 0000000..48b7999
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/contrib/stephan_boettcher_1 b/chrony_3_3/contrib/stephan_boettcher_1
new file mode 100644
index 0000000..e5eda11
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/contrib/wolfgang_weisselberg1 b/chrony_3_3/contrib/wolfgang_weisselberg1
new file mode 100644
index 0000000..2c41752
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/doc/Makefile b/chrony_3_3/doc/Makefile
new file mode 100644
index 0000000..76f74b7
--- /dev/null
+++ b/chrony_3_3/doc/Makefile
@@ -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 = /etc
+BINDIR = /usr/local/bin
+SBINDIR = /usr/local/sbin
+MANDIR = /usr/local/share/man
+DOCDIR = /usr/local/share/doc/chrony
+CHRONYRUNDIR = /var/run/chrony
+CHRONYVARDIR = /var/lib/chrony
+CHRONY_VERSION = 3.3
+DEFAULT_USER = root
+DEFAULT_HWCLOCK_FILE = 
+DEFAULT_PID_FILE = /var/run/chronyd.pid
+DEFAULT_RTC_DEVICE = /dev/rtc
+
+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/chrony_3_3/doc/Makefile.in b/chrony_3_3/doc/Makefile.in
new file mode 100644
index 0000000..1777da5
--- /dev/null
+++ b/chrony_3_3/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/chrony_3_3/doc/chrony.conf.adoc b/chrony_3_3/doc/chrony.conf.adoc
new file mode 100644
index 0000000..be39a27
--- /dev/null
+++ b/chrony_3_3/doc/chrony.conf.adoc
@@ -0,0 +1,2435 @@
+// 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 -4 (1/16th 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.
+*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 0 (1 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 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 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.
+*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 two
+requests have been sent to it without receiving a response. This option avoids
+the need to run the <<chronyc.adoc#offline,*offline*>> command from *chronyc*
+when disconnecting the network link, if it is safe to assume that the requests
+and responses will not be dropped in the network, e.g. in a trusted local
+network. (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.
+
+=== 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).
+*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.
+
+[[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_::
+*chronyd* always 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/chrony_3_3/doc/chrony.conf.man.in b/chrony_3_3/doc/chrony.conf.man.in
new file mode 100644
index 0000000..8a023bf
--- /dev/null
+++ b/chrony_3_3/doc/chrony.conf.man.in
@@ -0,0 +1,3947 @@
+'\" t
+.\"     Title: chrony.conf
+.\"    Author: [see the "AUTHORS" section]
+.\" Generator: Asciidoctor 1.5.6.1
+.\"      Date: 2018-04-04
+.\"    Manual: Configuration Files
+.\"    Source: chrony @CHRONY_VERSION@
+.\"  Language: English
+.\"
+.TH "CHRONY.CONF" "5" "2018-04-04" "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 \-4 (1/16th 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.
+.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 0 (1 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 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 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
+\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 two
+requests have been sent to it without receiving a response. This option avoids
+the need to run the \fBoffline\fP command from \fBchronyc\fP
+when disconnecting the network link, if it is safe to assume that the requests
+and responses will not be dropped in the network, e.g. in a trusted local
+network. (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
+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.
+.sp
+If the correction required is less than a specified threshold, a slew is used
+instead. This makes it safer to restart \fBchronyd\fP whilst the system is in
+normal operation.
+.sp
+The \fBinitstepslew\fP 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. \fBchronyd\fP then enters its normal operating mode.
+.sp
+An example of the use of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+initstepslew 30 foo.example.net bar.example.net
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+where 2 NTP servers are used to make the measurement. The \fI30\fP indicates that
+if the system\(cqs 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.
+.sp
+The \fBinitstepslew\fP 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 \fBlocal\fP directive, the master can be set up with
+an \fBinitstepslew\fP 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.
+.sp
+The \fBinitstepslew\fP directive is functionally similar to a combination of the
+\fBmakestep\fP and \fBserver\fP directives with the \fBiburst\fP
+option. The main difference is that the \fBinitstepslew\fP servers are used only
+before normal operation begins and that the foreground \fBchronyd\fP process waits
+for \fBinitstepslew\fP to finish before exiting. This is useful to prevent programs
+started in the boot sequence after \fBchronyd\fP from reading the clock before it
+has been stepped.
+.RE
+.sp
+\fBrefclock\fP \fIdriver\fP \fIparameter\fP[:\fIoption\fP,...] [\fIoption\fP]...
+.RS 4
+The \fBrefclock\fP 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 \fB:\fP and \fB,\fP characters).
+.sp
+There are four drivers included in \fBchronyd\fP:
+.sp
+\fBPPS\fP
+.RS 4
+Driver for the kernel PPS (pulse per second) API. The parameter is the path to
+the PPS device (typically \fI/dev/pps?\fP). 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
+\fBlocal\fP directive to allow synchronisation with some unknown but
+constant offset. The driver supports the following option:
+.sp
+\fBclear\fP
+.RS 4
+By default, the PPS refclock uses assert events (rising edge) for
+synchronisation. With this option, it will use clear events (falling edge)
+instead.
+.RE
+.RE
+.sp
+
+.RS 4
+Examples:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+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
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBSHM\fP
+.RS 4
+NTP shared memory driver. This driver uses a shared memory segment to receive
+samples from another process (e.g. \fBgpsd\fP). 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:
+.sp
+\fBperm\fP=\fImode\fP
+.RS 4
+This option specifies the permissions of the shared memory segment created by
+\fBchronyd\fP. They are specified as a numeric mode. The default value is 0600
+(read\-write access for owner only).
+.RE
+.RE
+.sp
+
+.RS 4
+.sp
+Examples:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+refclock SHM 0 poll 3 refid GPS1
+refclock SHM 1:perm=0644 refid GPS2
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBSOCK\fP
+.RS 4
+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
+\fBchronyd\fP 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 \fIrefclock_sock.c\fP file in the chrony
+source code.
+.sp
+An application which supports the SOCK protocol is the \fBgpsd\fP daemon. The path
+where \fBgpsd\fP expects the socket to be created is described in the \fBgpsd(8)\fP man
+page. For example:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+refclock SOCK /var/run/chrony.ttyS0.sock
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBPHC\fP
+.RS 4
+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 \fBoffset\fP option. Alternatively, the
+\fBpps\fP 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:
+.sp
+\fBnocrossts\fP
+.RS 4
+This option disables use of precise cross timestamping.
+.RE
+.sp
+\fBextpps\fP
+.RS 4
+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 \fBwidth\fP option to filter wrong
+PPS samples.
+.RE
+.sp
+\fBpin\fP=\fIindex\fP
+.RS 4
+This option specifies the index of the pin to which is connected the PPS
+signal. The default value is 0.
+.RE
+.sp
+\fBchannel\fP=\fIindex\fP
+.RS 4
+This option specifies the index of the channel for the PPS mode. The default
+value is 0.
+.RE
+.sp
+\fBclear\fP
+.RS 4
+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.
+.RE
+.RE
+.sp
+
+.RS 4
+.sp
+Examples:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+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
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.RE
+.sp
+
+.RS 4
+The \fBrefclock\fP directive supports the following options:
+.sp
+\fBpoll\fP \fIpoll\fP
+.RS 4
+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
+\fBchronyd\fP 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.
+.RE
+.sp
+\fBdpoll\fP \fIdpoll\fP
+.RS 4
+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).
+.RE
+.sp
+\fBrefid\fP \fIrefid\fP
+.RS 4
+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.
+.RE
+.sp
+\fBlock\fP \fIrefid\fP
+.RS 4
+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.
+.RE
+.sp
+\fBrate\fP \fIrate\fP
+.RS 4
+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 \fBdpoll\fP has to be specified (\-3 for
+a 5Hz signal). The default is 1.
+.RE
+.sp
+\fBmaxlockage\fP \fIpulses\fP
+.RS 4
+This option specifies in number of pulses how old can be samples from the
+refclock specified by the \fBlock\fP 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.
+.RE
+.sp
+\fBwidth\fP \fIwidth\fP
+.RS 4
+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.
+.RE
+.sp
+\fBpps\fP
+.RS 4
+This options forces \fBchronyd\fP 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.
+.RE
+.sp
+\fBoffset\fP \fIoffset\fP
+.RS 4
+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.
+.RE
+.sp
+\fBdelay\fP \fIdelay\fP
+.RS 4
+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).
+.RE
+.sp
+\fBstratum\fP \fIstratum\fP
+.RS 4
+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.
+.RE
+.sp
+\fBprecision\fP \fIprecision\fP
+.RS 4
+This option sets the precision of the reference clock (in seconds). The default
+value is the estimated precision of the system clock.
+.RE
+.sp
+\fBmaxdispersion\fP \fIdispersion\fP
+.RS 4
+Maximum allowed dispersion for filtered samples (in seconds). Samples with
+larger estimated dispersion are ignored. By default, this limit is disabled.
+.RE
+.sp
+\fBfilter\fP \fIsamples\fP
+.RS 4
+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.
+.RE
+.sp
+\fBprefer\fP
+.RS 4
+Prefer this source over sources without the prefer option.
+.RE
+.sp
+\fBnoselect\fP
+.RS 4
+Never select this source. This is useful for monitoring or with sources which
+are not very accurate, but are locked with a PPS refclock.
+.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 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.
+.RE
+.sp
+\fBtai\fP
+.RS 4
+This option indicates that the reference clock keeps time in TAI instead of UTC
+and that \fBchronyd\fP should correct its offset by the current TAI\-UTC offset. The
+\fBleapsectz\fP 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.
+.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
+.RE
+.sp
+\fBmanual\fP
+.RS 4
+The \fBmanual\fP directive enables support at run\-time for the
+\fBsettime\fP command in \fBchronyc\fP. If no \fBmanual\fP
+directive is included, any attempt to use the \fBsettime\fP command in \fBchronyc\fP
+will be met with an error message.
+.sp
+Note that the \fBsettime\fP command can be enabled at run\-time using
+the \fBmanual\fP command in \fBchronyc\fP. (The idea of the two
+commands is that the \fBmanual\fP command controls the manual clock driver\(cqs
+behaviour, whereas the \fBsettime\fP command allows samples of manually entered
+time to be provided.)
+.RE
+.sp
+\fBacquisitionport\fP \fIport\fP
+.RS 4
+By default, \fBchronyd\fP 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 \fBacquisitionport\fP 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.
+.sp
+It can be set to the same port as is used by the NTP server (which can be
+configured with the \fBport\fP directive) to use only one socket for all
+NTP packets.
+.sp
+An example of the \fBacquisitionport\fP directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+acquisitionport 1123
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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.
+.RE
+.sp
+\fBbindacqaddress\fP \fIaddress\fP
+.RS 4
+The \fBbindacqaddress\fP directive sets the network interface to which
+\fBchronyd\fP will bind its NTP client sockets. The syntax is similar to the
+\fBbindaddress\fP and \fBbindcmdaddress\fP
+directives.
+.sp
+For each of the IPv4 and IPv6 protocols, only one \fBbindacqaddress\fP directive
+can be specified.
+.RE
+.sp
+\fBdumpdir\fP \fIdirectory\fP
+.RS 4
+To compute the rate of gain or loss of time, \fBchronyd\fP has to store a
+measurement history for each of the time sources it uses.
+.sp
+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, \fBchronyd\fP 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.)
+.sp
+For such systems, it is possible to save the measurement history across
+restarts of \fBchronyd\fP (assuming no changes are made to the system clock
+behaviour whilst it is not running). The \fBdumpdir\fP directive defines the
+directory where the measurement histories are saved when \fBchronyd\fP exits,
+or the \fBdump\fP command in \fBchronyc\fP is issued.
+.sp
+An example of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+dumpdir @CHRONYRUNDIR@
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+A source whose IP address is \fI1.2.3.4\fP would have its measurement history saved
+in the file \fI@CHRONYRUNDIR@/1.2.3.4.dat\fP. History of reference clocks is saved
+to files named by their reference ID in form of \fIrefid:XXXXXXXX.dat\fP.
+.RE
+.sp
+\fBmaxsamples\fP \fIsamples\fP
+.RS 4
+The \fBmaxsamples\fP directive sets the default maximum number of samples that
+\fBchronyd\fP should keep for each source. This setting can be overridden for
+individual sources in the \fBserver\fP and \fBrefclock\fP
+directives. The default value is 0, which disables the configurable limit. The
+useful range is 4 to 64.
+.RE
+.sp
+\fBminsamples\fP \fIsamples\fP
+.RS 4
+The \fBminsamples\fP directive sets the default minimum number of samples that
+\fBchronyd\fP should keep for each source. This setting can be overridden for
+individual sources in the \fBserver\fP and \fBrefclock\fP
+directives. The default value is 6. The useful range is 4 to 64.
+.RE
+.SS "Source selection"
+.sp
+\fBcombinelimit\fP \fIlimit\fP
+.RS 4
+When \fBchronyd\fP 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.
+.sp
+The \fBcombinelimit\fP 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.
+.sp
+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.
+.RE
+.sp
+\fBmaxdistance\fP \fIdistance\fP
+.RS 4
+The \fBmaxdistance\fP 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.
+.sp
+By default, the maximum root distance is 3 seconds.
+.sp
+Setting \fBmaxdistance\fP 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.
+.RE
+.sp
+\fBmaxjitter\fP \fIjitter\fP
+.RS 4
+The \fBmaxjitter\fP 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.
+.sp
+By default, the maximum jitter is 1 second.
+.RE
+.sp
+\fBminsources\fP \fIsources\fP
+.RS 4
+The \fBminsources\fP 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.
+.sp
+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.
+.RE
+.sp
+\fBreselectdist\fP \fIdistance\fP
+.RS 4
+When \fBchronyd\fP 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 \fBreselectdist\fP directive. By default, the
+distance is 100 microseconds.
+.RE
+.sp
+\fBstratumweight\fP \fIdistance\fP
+.RS 4
+The \fBstratumweight\fP directive sets how much distance should be added per
+stratum to the synchronisation distance when \fBchronyd\fP selects the
+synchronisation source from available sources.
+.sp
+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.
+.RE
+.SS "System clock"
+.sp
+\fBcorrtimeratio\fP \fIratio\fP
+.RS 4
+When \fBchronyd\fP 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.
+.sp
+The \fBcorrtimeratio\fP 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.
+.sp
+Increasing \fBcorrtimeratio\fP improves the overall frequency error of the system
+clock, but increases the overall time error as the corrections take longer.
+.sp
+By default, the ratio is set to 3, the time accuracy of the clock is preferred
+over its frequency accuracy.
+.sp
+The maximum allowed slew rate can be set by the \fBmaxslewrate\fP
+directive. The current remaining correction is shown in the
+\fBtracking\fP report as the \fBSystem time\fP value.
+.RE
+.sp
+\fBdriftfile\fP \fIfile\fP
+.RS 4
+One of the main activities of the \fBchronyd\fP program is to work out the rate at
+which the system clock gains or loses time relative to real time.
+.sp
+Whenever \fBchronyd\fP computes a new value of the gain or loss rate, it is desirable
+to record it somewhere. This allows \fBchronyd\fP 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.)
+.sp
+The \fBdriftfile\fP directive allows a file to be specified into which \fBchronyd\fP
+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.
+.sp
+An example of the driftfile directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+driftfile @CHRONYVARDIR@/drift
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBfallbackdrift\fP \fImin\-interval\fP \fImax\-interval\fP
+.RS 4
+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.
+.sp
+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:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+fallbackdrift 16 19
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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 \(oqNot synchronised\(cq.
+.sp
+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.
+.RE
+.sp
+\fBleapsecmode\fP \fImode\fP
+.RS 4
+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.
+.sp
+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 \fBleapsecmode\fP directive selects how
+that error is corrected. There are four options:
+.sp
+\fBsystem\fP
+.RS 4
+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).
+.RE
+.sp
+\fBstep\fP
+.RS 4
+This is similar to the \fBsystem\fP mode, except the clock is stepped by
+\fBchronyd\fP instead of the kernel. It can be useful to avoid bugs in the kernel
+code that would be executed in the \fBsystem\fP mode. This is the default mode
+when the system driver does not support leap seconds.
+.RE
+.sp
+\fBslew\fP
+.RS 4
+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 \fBsystem\fP and \fBstep\fP 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
+\fBmaxslewrate\fP value the correction takes 12 seconds.
+.RE
+.sp
+\fBignore\fP
+.RS 4
+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.
+.RE
+.RE
+.sp
+
+.RS 4
+.sp
+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
+\fBslew\fP mode can be combined with the \fBsmoothtime\fP directive to
+enable a server leap smear.
+.sp
+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.
+.sp
+This feature must be used carefully, because the server is intentionally not
+serving its best estimate of the true time.
+.sp
+A recommended configuration to enable a server leap smear is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+leapsecmode slew
+maxslewrate 1000
+smoothtime 400 0.001 leaponly
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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
+\fBleaponly\fP option makes the duration of the leap smear constant and allows the
+clients to safely synchronise with multiple identically configured leap
+smearing servers.
+.RE
+.sp
+\fBleapsectz\fP \fItimezone\fP
+.RS 4
+This directive specifies a timezone in the system tz database which \fBchronyd\fP
+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
+\fIright/UTC\fP timezone.
+.sp
+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 \fBchronyd\fP.
+.sp
+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.
+.sp
+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. \fBleapsecmode\fP is set to \fBsystem\fP.
+.sp
+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.
+.sp
+An example of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+leapsectz right/UTC
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The following shell command verifies that the timezone contains leap seconds
+and can be used with this directive:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+$ TZ=right/UTC date \-d \(aqDec 31 2008 23:59:60\(aq
+Wed Dec 31 23:59:60 UTC 2008
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBmakestep\fP \fIthreshold\fP \fIlimit\fP
+.RS 4
+Normally \fBchronyd\fP 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.
+.sp
+This directive forces \fBchronyd\fP to step the system clock if the adjustment is
+larger than a threshold value, but only if there were no more clock updates
+since \fBchronyd\fP was started than a specified limit (a negative value can be
+used to disable the limit).
+.sp
+This is particularly useful when using reference clocks, because the
+\fBinitstepslew\fP directive works only with NTP sources.
+.sp
+An example of the use of this directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+makestep 0.1 3
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This would step the system clock if the adjustment is larger than 0.1 seconds, but
+only in the first three clock updates.
+.RE
+.sp
+\fBmaxchange\fP \fIoffset\fP \fIstart\fP \fIignore\fP
+.RS 4
+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 \fBchronyd\fP will give up and exit (a negative value can be used to never
+exit). In both cases a message is sent to syslog.
+.sp
+An example of the use of this directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+maxchange 1000 1 2
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+After the first clock update, \fBchronyd\fP will check the offset on every clock
+update, it will ignore two adjustments larger than 1000 seconds and exit on
+another one.
+.RE
+.sp
+\fBmaxclockerror\fP \fIerror\-in\-ppm\fP
+.RS 4
+The \fBmaxclockerror\fP 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.
+.sp
+By default, the maximum error is 1 ppm.
+.sp
+Typical values for \fIerror\-in\-ppm\fP might be 10 for a low quality clock and 0.1
+for a high quality clock using a temperature compensated crystal oscillator.
+.RE
+.sp
+\fBmaxdrift\fP \fIdrift\-in\-ppm\fP
+.RS 4
+This directive specifies the maximum assumed drift (frequency error) of the
+system clock. It limits the frequency adjustment that \fBchronyd\fP 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).
+.sp
+By default, the maximum assumed drift is 500000 ppm, i.e. the adjustment is
+limited by the system driver rather than this directive.
+.RE
+.sp
+\fBmaxupdateskew\fP \fIskew\-in\-ppm\fP
+.RS 4
+One of \fBchronyd\fP\(cqs tasks is to work out how fast or slow the computer\(cqs clock
+runs relative to its reference sources. In addition, it computes an estimate of
+the error bounds around the estimated value.
+.sp
+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.
+.sp
+The \fBmaxupdateskew\fP 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.
+.sp
+Typical values for \fIskew\-in\-ppm\fP might be 100 for a dial\-up connection to
+servers over a phone line, and 5 or 10 for a computer on a LAN.
+.sp
+It should be noted that this is not the only means of protection against using
+unreliable estimates. At all times, \fBchronyd\fP 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 \fBchronyd\fP
+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.
+.RE
+.sp
+\fBmaxslewrate\fP \fIrate\-in\-ppm\fP
+.RS 4
+The \fBmaxslewrate\fP directive sets the maximum rate at which \fBchronyd\fP is allowed
+to slew the time. It limits the slew rate controlled by the correction time
+ratio (which can be set by the \fBcorrtimeratio\fP directive) and
+is effective only on systems where \fBchronyd\fP is able to control the rate (i.e.
+all supported systems with the exception of macOS 12 or earlier).
+.sp
+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 \fBmaxslewrate\fP on FreeBSD, NetBSD, macOS 10.13+ to a value between 500
+ppm and 5000 ppm will effectively set it to 500 ppm.
+.sp
+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.
+.sp
+By default, the maximum slew rate is set to 83333.333 ppm (one twelfth).
+.RE
+.sp
+\fBtempcomp\fP \fIfile\fP \fIinterval\fP \fIT0\fP \fIk0\fP \fIk1\fP \fIk2\fP, \fBtempcomp\fP \fIfile\fP \fIinterval\fP \fIpoints\-file\fP
+.RS 4
+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.
+.sp
+If there are temperature measurements available from a sensor close to the
+oscillator, the \fBtempcomp\fP directive can be used to compensate for the changes
+in the temperature and improve the stability and accuracy of the clock.
+.sp
+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 \fItracking.log\fP file is more stable and the maximum
+reached offset is smaller.
+.sp
+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 \fIT0\fP, \fIk0\fP, \fIk1\fP, \fIk2\fP.
+.sp
+The frequency compensation is calculated (in ppm) as
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+k0 + (T \- T0) * k1 + (T \- T0)^2 * k2
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The result has to be between \-10 ppm and 10 ppm, otherwise the measurement is
+considered invalid and will be ignored. The \fIk0\fP coefficient can be adjusted to
+keep the compensation in that range.
+.sp
+An example of the use is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 26000 0.0 0.000183 0.0
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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.
+.sp
+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.
+.sp
+An example is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 /etc/chrony.tempcomp
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+where the \fI/etc/chrony.tempcomp\fP file could have
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+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
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Valid measurements with corresponding compensations are logged to the
+\fItempcomp.log\fP file if enabled by the \fBlog tempcomp\fP directive.
+.RE
+.SS "NTP server"
+.sp
+\fBallow\fP [\fBall\fP] [\fIsubnet\fP]
+.RS 4
+The \fBallow\fP directive is used to designate a particular subnet from which NTP
+clients are allowed to access the computer as an NTP server.
+.sp
+The default is that no clients are allowed access, i.e. \fBchronyd\fP operates
+purely as an NTP client. If the \fBallow\fP directive is used, \fBchronyd\fP will be
+both a client of its servers, and a server to other clients.
+.sp
+Examples of the use of the directive are as follows:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+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
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The first directive allows a node with IPv4 address \fI1.2.3.4\fP to be an NTP
+client of this computer.
+The second directive allows any node with an IPv4 address of the form \fI1.2.x.y\fP
+(with \fIx\fP and \fIy\fP arbitrary) to be an NTP client of this computer. Likewise,
+the third directive allows any node with an IPv4 address of the form \fI3.4.5.x\fP
+to have client NTP access. The fourth and fifth forms allow access from any
+node with an IPv4 address of the form \fI6.7.8.x\fP, \fI6.7.9.x\fP, \fI6.7.10.x\fP or
+\fI6.7.11.x\fP (with \fIx\fP 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).
+.sp
+A second form of the directive, \fBallow all\fP, has a greater effect, depending on
+the ordering of directives in the configuration file. To illustrate the effect,
+consider the two examples:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+allow 1.2.3.4
+deny 1.2.3
+allow 1.2
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+and
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+allow 1.2.3.4
+deny 1.2.3
+allow all 1.2
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+In the first example, the effect is the same regardless of what order the three
+directives are given in. So the \fI1.2.x.y\fP subnet is allowed access, except for
+the \fI1.2.3.x\fP subnet, which is denied access, however the host \fI1.2.3.4\fP is
+allowed access.
+.sp
+In the second example, the \fBallow all 1.2\fP directives overrides the effect of
+\fIany\fP 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 \fBchronyc\fP with the
+\fBallow all\fP command.
+.sp
+The directive allows a hostname to be specified instead of an IP address, but
+the name must be resolvable when \fBchronyd\fP is started (i.e. \fBchronyd\fP needs
+to be started when the network is already up and DNS is working).
+.sp
+Note, if the \fBinitstepslew\fP 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.
+.RE
+.sp
+\fBdeny\fP [\fBall\fP] [\fIsubnet\fP]
+.RS 4
+This is similar to the \fBallow\fP directive, except that it denies NTP
+client access to a particular subnet or host, rather than allowing it.
+.sp
+The syntax is identical.
+.sp
+There is also a \fBdeny all\fP directive with similar behaviour to the \fBallow all\fP
+directive.
+.RE
+.sp
+\fBbindaddress\fP \fIaddress\fP
+.RS 4
+The \fBbindaddress\fP directive binds the socket on which \fBchronyd\fP 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 \fBchronyd\fP is
+started.
+.sp
+An example of the use of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+bindaddress 192.168.1.1
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Currently, for each of the IPv4 and IPv6 protocols, only one \fBbindaddress\fP
+directive can be specified. Therefore, it is not useful on computers which
+should serve NTP on multiple network interfaces.
+.RE
+.sp
+\fBbroadcast\fP \fIinterval\fP \fIaddress\fP [\fIport\fP]
+.RS 4
+The \fBbroadcast\fP directive is used to declare a broadcast address to which
+chronyd should send packets in the NTP broadcast mode (i.e. make \fBchronyd\fP act
+as a broadcast server). Broadcast clients on that subnet will be able to
+synchronise.
+.sp
+The syntax is as follows:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+broadcast 30 192.168.1.255
+broadcast 60 192.168.2.255 12123
+broadcast 60 ff02::101
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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
+\fBchronyd\fP is running.
+.sp
+You can have more than 1 \fBbroadcast\fP directive if you have more than 1 network
+interface onto which you want to send NTP broadcast packets.
+.sp
+\fBchronyd\fP 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.
+.sp
+If \fBntpd\fP 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 \fBallow\fP
+directive.
+.RE
+.sp
+\fBclientloglimit\fP \fIlimit\fP
+.RS 4
+This directive specifies the maximum amount of memory that \fBchronyd\fP is allowed
+to allocate for logging of client accesses and the state that \fBchronyd\fP 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.
+.sp
+In older \fBchrony\fP versions if the limit was set to 0, the memory allocation was
+unlimited.
+.sp
+An example of the use of this directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+clientloglimit 1048576
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBnoclientlog\fP
+.RS 4
+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 \fBclients\fP command in \fBchronyc\fP. This option
+also effectively disables server support for the NTP interleaved mode.
+.RE
+.sp
+\fBlocal\fP [\fIoption\fP]...
+.RS 4
+The \fBlocal\fP directive enables a local reference mode, which allows \fBchronyd\fP
+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.
+.sp
+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.
+.sp
+The \fBlocal\fP directive has the following options:
+.sp
+\fBstratum\fP \fIstratum\fP
+.RS 4
+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.
+.sp
+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.
+.RE
+.sp
+\fBdistance\fP \fIdistance\fP
+.RS 4
+This option sets the threshold for the root distance which will activate the local
+reference. If \fBchronyd\fP 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.
+.sp
+The current root distance can be calculated from root delay and root dispersion
+(reported by the \fBtracking\fP command in \fBchronyc\fP) as:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+distance = delay / 2 + dispersion
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBorphan\fP
+.RS 4
+This option enables a special \(oqorphan\(cq mode, where sources with stratum equal
+to the local \fIstratum\fP 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.
+.sp
+This allows multiple servers in the network to use the same \fBlocal\fP
+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 \fBlocal\fP 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.
+.sp
+The \fBorphan\fP mode is compatible with the \fBntpd\fP\(cqs orphan mode (enabled by the
+\fBtos orphan\fP command).
+.RE
+.RE
+.sp
+
+.RS 4
+.sp
+An example of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+local stratum 10 orphan
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBntpsigndsocket\fP \fIdirectory\fP
+.RS 4
+This directive specifies the location of the Samba \fBntp_signd\fP socket when it
+is running as a Domain Controller (DC). If \fBchronyd\fP is compiled with this
+feature, responses to MS\-SNTP clients will be signed by the \fBsmbd\fP daemon.
+.sp
+Note that MS\-SNTP requests are not authenticated and any client that is allowed
+to access the server by the \fBallow\fP directive, or the
+\fBallow\fP command in \fBchronyc\fP, can get an MS\-SNTP
+response signed with a trust account\(cqs password and try to crack the password
+in a brute\-force attack. Access to the server should be carefully controlled.
+.sp
+An example of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+ntpsigndsocket /var/lib/samba/ntp_signd
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBport\fP \fIport\fP
+.RS 4
+This option allows you to configure the port on which \fBchronyd\fP will listen for
+NTP requests. The port will be open only when an address is allowed by the
+\fBallow\fP directive or the \fBallow\fP command in
+\fBchronyc\fP, an NTP peer is configured, or the broadcast server mode is enabled.
+.sp
+The default value is 123, the standard NTP port. If set to 0, \fBchronyd\fP 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
+\fBacquisitionport\fP directive.
+.RE
+.sp
+\fBratelimit\fP [\fIoption\fP]...
+.RS 4
+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 \fBclientloglimit\fP
+directive.
+.sp
+The \fBratelimit\fP directive supports a number of options (which can be defined
+in any order):
+.sp
+\fBinterval\fP
+.RS 4
+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).
+.RE
+.sp
+\fBburst\fP
+.RS 4
+This option sets the maximum number of responses that can be sent in a burst,
+temporarily exceeding the limit specified by the \fBinterval\fP option. This is
+useful for clients that make rapid measurements on start (e.g. \fBchronyd\fP with
+the \fBiburst\fP option). The default value is 8. The minimum value is 1 and the
+maximum value is 255.
+.RE
+.sp
+\fBleak\fP
+.RS 4
+This option sets the rate at which responses are randomly allowed even if the
+limits specified by the \fBinterval\fP and \fBburst\fP 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.
+.RE
+.RE
+.sp
+
+.RS 4
+.sp
+An example use of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+ratelimit interval 1 burst 16
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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 \fBleak\fP of 2).
+.RE
+.sp
+\fBsmoothtime\fP \fImax\-freq\fP \fImax\-wander\fP [\fBleaponly\fP]
+.RS 4
+The \fBsmoothtime\fP directive can be used to enable smoothing of the time that
+\fBchronyd\fP 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\(cqs clock, for example after being offline for a longer
+time.
+.sp
+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.
+.sp
+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 \fBmakestep\fP directive or the
+\fBmakestep\fP command in \fBchronyc\fP. The process can be
+reset without stepping the clock by the \fBsmoothtime
+reset\fP command.
+.sp
+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). \fBleaponly\fP
+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 \fBleaponly\fP
+option is useful in a combination with the \fBleapsecmode slew\fP
+directive to allow the clients to use multiple time smoothing servers safely.
+.sp
+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 \fBsmoothtime
+activate\fP command, which is particularly useful when the clock is
+synchronised only with manual input and the skew is always larger than the
+threshold. The \fBsmoothing\fP command can be used to
+monitor the process.
+.sp
+An example suitable for clients using \fBntpd\fP and 1024 second polling interval
+could be:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+smoothtime 400 0.001
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+An example suitable for clients using \fBchronyd\fP on Linux could be:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+smoothtime 50000 0.01
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SS "Command and monitoring access"
+.sp
+\fBbindcmdaddress\fP \fIaddress\fP
+.RS 4
+The \fBbindcmdaddress\fP directive allows you to specify an IP address of an
+interface on which \fBchronyd\fP will listen for monitoring command packets (issued
+by \fBchronyc\fP). On systems other than Linux, the address of the interface needs
+to be already configured when \fBchronyd\fP is started.
+.sp
+This directive can also change the path of the Unix domain command socket,
+which is used by \fBchronyc\fP to send configuration commands. The socket must be
+in a directory that is accessible only by the root or \fIchrony\fP user. The
+directory will be created on start if it does not exist. The compiled\-in default
+path of the socket is \fI@CHRONYRUNDIR@/chronyd.sock\fP. The socket can be
+disabled by setting the path to \fI/\fP.
+.sp
+By default, \fBchronyd\fP binds to the loopback interface (with addresses
+\fI127.0.0.1\fP and \fI::1\fP). This blocks all access except from localhost. To listen
+for command packets on all interfaces, you can add the lines:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+bindcmdaddress 0.0.0.0
+bindcmdaddress ::
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+to the configuration file.
+.sp
+For each of the IPv4, IPv6, and Unix domain protocols, only one
+\fBbindcmdaddress\fP directive can be specified.
+.sp
+An example that sets the path of the Unix domain command socket is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+bindcmdaddress /var/run/chrony/chronyd.sock
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBcmdallow\fP [\fBall\fP] [\fIsubnet\fP]
+.RS 4
+This is similar to the \fBallow\fP directive, except that it allows
+monitoring access (rather than NTP client access) to a particular subnet or
+host. (By \(oqmonitoring access\(cq is meant that \fBchronyc\fP can be run on those
+hosts and retrieve monitoring data from \fBchronyd\fP on this computer.)
+.sp
+The syntax is identical to the \fBallow\fP directive.
+.sp
+There is also a \fBcmdallow all\fP directive with similar behaviour to the \fBallow
+all\fP directive (but applying to monitoring access in this case, of course).
+.sp
+Note that \fBchronyd\fP has to be configured with the
+\fBbindcmdaddress\fP directive to not listen only on the
+loopback interface to actually allow remote access.
+.RE
+.sp
+\fBcmddeny\fP [\fBall\fP] [\fIsubnet\fP]
+.RS 4
+This is similar to the \fBcmdallow\fP directive, except that it denies
+monitoring access to a particular subnet or host, rather than allowing it.
+.sp
+The syntax is identical.
+.sp
+There is also a \fBcmddeny all\fP directive with similar behaviour to the \fBcmdallow
+all\fP directive.
+.RE
+.sp
+\fBcmdport\fP \fIport\fP
+.RS 4
+The \fBcmdport\fP directive allows the port that is used for run\-time monitoring
+(via the \fBchronyc\fP program) to be altered from its default (323). If set to 0,
+\fBchronyd\fP will not open the port, this is useful to disable \fBchronyc\fP
+access from the Internet. (It does not disable the Unix domain command socket.)
+.sp
+An example shows the syntax:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+cmdport 257
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This would make \fBchronyd\fP use UDP 257 as its command port. (\fBchronyc\fP would
+need to be run with the \fB\-p 257\fP switch to inter\-operate correctly.)
+.RE
+.sp
+\fBcmdratelimit\fP [\fIoption\fP]...
+.RS 4
+This directive enables response rate limiting for command packets. It is
+similar to the \fBratelimit\fP directive, except responses to
+localhost are never limited and the default interval is \-4 (16 packets per
+second).
+.sp
+An example of the use of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+cmdratelimit interval 2
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SS "Real\-time clock (RTC)"
+.sp
+\fBhwclockfile\fP \fIfile\fP
+.RS 4
+The \fBhwclockfile\fP directive sets the location of the adjtime file which is
+used by the \fBhwclock\fP program on Linux. \fBchronyd\fP parses the file to find out
+if the RTC keeps local time or UTC. It overrides the \fBrtconutc\fP
+directive.
+.sp
+The compiled\-in default value is \(aq\fI@DEFAULT_HWCLOCK_FILE@\fP\(aq.
+.sp
+An example of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+hwclockfile /etc/adjtime
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBrtcautotrim\fP \fIthreshold\fP
+.RS 4
+The \fBrtcautotrim\fP 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, \fBchronyd\fP will
+trim the RTC as if the \fBtrimrtc\fP command in \fBchronyc\fP
+was issued.
+.sp
+This directive is effective only with the \fBrtcfile\fP directive.
+.sp
+An example of the use of this directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+rtcautotrim 30
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This would set the threshold error to 30 seconds.
+.RE
+.sp
+\fBrtcdevice\fP \fIdevice\fP
+.RS 4
+The \fBrtcdevice\fP directive sets the path to the device file for accessing the
+RTC. The default path is \fI@DEFAULT_RTC_DEVICE@\fP.
+.RE
+.sp
+\fBrtcfile\fP \fIfile\fP
+.RS 4
+The \fBrtcfile\fP directive defines the name of the file in which \fBchronyd\fP can
+save parameters associated with tracking the accuracy of the RTC.
+.sp
+An example of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+rtcfile @CHRONYVARDIR@/rtc
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+\fBchronyd\fP saves information in this file when it exits and when the \fBwritertc\fP
+command is issued in \fBchronyc\fP. The information saved is the RTC\(cqs error at
+some epoch, that epoch (in seconds since January 1 1970), and the rate at which
+the RTC gains or loses time.
+.sp
+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 \fBrtcfile\fP directive and the \fB\-s\fP command\-line
+option to \fBchronyd\fP) if the following three conditions apply:
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+You are running Linux.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+The kernel is compiled with extended real\-time clock support (i.e. the
+\fI/dev/rtc\fP device is capable of doing useful things).
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+You do not have other applications that need to make use of \fI/dev/rtc\fP at all.
+.RE
+.RE
+.sp
+\fBrtconutc\fP
+.RS 4
+\fBchronyd\fP 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.
+.sp
+If you keep the RTC on local time and your computer is off when daylight saving
+(summer time) starts or ends, the computer\(cqs system time will be one hour in
+error when you next boot and start chronyd.
+.sp
+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.
+.sp
+If the \fBrtconutc\fP directive appears, it means the RTC is required to keep UTC.
+The directive takes no arguments. It is equivalent to specifying the \fB\-u\fP
+switch to the Linux \fBhwclock\fP program.
+.sp
+Note that this setting is overridden when the \fBhwclockfile\fP
+directive is specified.
+.RE
+.sp
+\fBrtcsync\fP
+.RS 4
+The \fBrtcsync\fP directive enables a mode where the system time is periodically
+copied to the RTC and \fBchronyd\fP does not try to track its drift. This directive
+cannot be used with the \fBrtcfile\fP directive.
+.sp
+On Linux, the RTC copy is performed by the kernel every 11 minutes.
+.sp
+On macOS, \fBchronyd\fP will perform the RTC copy every 60 minutes
+when the system clock is in a synchronised state.
+.sp
+On other systems this directive does nothing.
+.RE
+.SS "Logging"
+.sp
+\fBlog\fP [\fIoption\fP]...
+.RS 4
+The \fBlog\fP directive indicates that certain information is to be logged.
+The log files are written to the directory specified by the \fBlogdir\fP
+directive. A banner is periodically written to the files to indicate the
+meanings of the columns.
+.sp
+\fBrawmeasurements\fP
+.RS 4
+This option logs the raw NTP measurements and related information to a file
+called \fImeasurements.log\fP. 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.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+2016\-11\-09 05:40:50 203.0.113.15    N  2 111 111 1111  10 10 1.0 \(rs
+   \-4.966e\-03  2.296e\-01  1.577e\-05  1.615e\-01  7.446e\-03 CB00717B 4B D K
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The columns are as follows (the quantities in square brackets are the values
+from the example line above):
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+Date [2015\-10\-13]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+Hour:Minute:Second. Note that the date\-time pair is expressed in UTC, not the
+local time zone. [05:40:50]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+IP address of server or peer from which measurement came [203.0.113.15]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 4." 4.2
+.\}
+Leap status (\fIN\fP means normal, \fI+\fP means that the last minute of the current
+month has 61 seconds, \fI\-\fP means that the last minute of the month has 59
+seconds, \fI?\fP means the remote computer is not currently synchronised.) [N]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 5.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 5." 4.2
+.\}
+Stratum of remote computer. [2]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 6.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 6." 4.2
+.\}
+RFC 5905 tests 1 through 3 (1=pass, 0=fail) [111]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 7.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 7." 4.2
+.\}
+RFC 5905 tests 5 through 7 (1=pass, 0=fail) [111]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 8.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 8." 4.2
+.\}
+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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 9.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 9." 4.2
+.\}
+Local poll [10]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 10.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 10." 4.2
+.\}
+Remote poll [10]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 11.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 11." 4.2
+.\}
+\(oqScore\(cq (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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 12.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 12." 4.2
+.\}
+The estimated local clock error (\fItheta\fP in RFC 5905). Positive indicates
+that the local clock is slow of the remote source. [\-4.966e\-03]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 13.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 13." 4.2
+.\}
+The peer delay (\fIdelta\fP in RFC 5905). [2.296e\-01]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 14.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 14." 4.2
+.\}
+The peer dispersion (\fIepsilon\fP in RFC 5905). [1.577e\-05]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 15.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 15." 4.2
+.\}
+The root delay (\fIDELTA\fP in RFC 5905). [1.615e\-01]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 16.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 16." 4.2
+.\}
+The root dispersion (\fIEPSILON\fP in RFC 5905). [7.446e\-03]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 17.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 17." 4.2
+.\}
+Reference ID of the server\(cqs source as a hexadecimal number. [CB00717B]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 18.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 18." 4.2
+.\}
+NTP mode of the received packet (\fI1\fP=active peer, \fI2\fP=passive peer,
+\fI4\fP=server, \fIB\fP=basic, \fII\fP=interleaved). [4B]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 19.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 19." 4.2
+.\}
+Source of the local transmit timestamp
+(\fID\fP=daemon, \fIK\fP=kernel, \fIH\fP=hardware). [D]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 20.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 20." 4.2
+.\}
+Source of the local receive timestamp
+(\fID\fP=daemon, \fIK\fP=kernel, \fIH\fP=hardware). [K]
+.RE
+.RE
+.sp
+\fBmeasurements\fP
+.RS 4
+This option is identical to the \fBrawmeasurements\fP 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\(cqs performance.
+.RE
+.sp
+\fBstatistics\fP
+.RS 4
+This option logs information about the regression processing to a file called
+\fIstatistics.log\fP. An example line (which actually appears as a single line in
+the file) from the log file is shown below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+2016\-08\-10 05:40:50 203.0.113.15     6.261e\-03 \-3.247e\-03 \(rs
+     2.220e\-03  1.874e\-06  1.080e\-06 7.8e\-02  16   0   8  0.00
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The columns are as follows (the quantities in square brackets are the values
+from the example line above):
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+Date [2015\-07\-22]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+Hour:Minute:Second. Note that the date\-time pair is expressed in
+UTC, not the local time zone. [05:40:50]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+IP address of server or peer from which measurement comes [203.0.113.15]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 4." 4.2
+.\}
+The estimated standard deviation of the measurements from the source (in
+seconds). [6.261e\-03]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 5.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 5." 4.2
+.\}
+The estimated offset of the source (in seconds, positive means the local
+clock is estimated to be fast, in this case). [\-3.247e\-03]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 6.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 6." 4.2
+.\}
+The estimated standard deviation of the offset estimate (in seconds).
+[2.220e\-03]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 7.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 7." 4.2
+.\}
+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, \fInot\fP to the local clock without any compensation.
+[1.874e\-06]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 8.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 8." 4.2
+.\}
+The estimated error in the rate value (in seconds per second). [1.080e\-06].
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 9.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 9." 4.2
+.\}
+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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 10.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 10." 4.2
+.\}
+The number of measurements currently being used for the regression
+algorithm. [16]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 11.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 11." 4.2
+.\}
+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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 12.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 12." 4.2
+.\}
+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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 13.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 13." 4.2
+.\}
+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]
+.RE
+.RE
+.sp
+\fBtracking\fP
+.RS 4
+This option logs changes to the estimate of the system\(cqs gain or loss rate, and
+any slews made, to a file called \fItracking.log\fP. An example line (which
+actually appears as a single line in the file) from the log file is shown
+below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+2017\-08\-22 13:22:36 203.0.113.15     2     \-3.541      0.075 \-8.621e\-06 N \(rs
+            2  2.940e\-03 \-2.084e\-04  1.534e\-02  3.472e\-04  8.304e\-03
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The columns are as follows (the quantities in square brackets are the
+values from the example line above) :
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+Date [2017\-08\-22]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+Hour:Minute:Second. Note that the date\-time pair is expressed in UTC, not the
+local time zone. [13:22:36]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+The IP address of the server or peer to which the local system is synchronised.
+[203.0.113.15]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 4." 4.2
+.\}
+The stratum of the local system. [2]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 5.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 5." 4.2
+.\}
+The local system frequency (in ppm, positive means the local system runs fast
+of UTC). [\-3.541]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 6.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 6." 4.2
+.\}
+The error bounds on the frequency (in ppm). [0.075]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 7.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 7." 4.2
+.\}
+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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 8.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 8." 4.2
+.\}
+Leap status (\fIN\fP means normal, \fI+\fP means that the last minute of this month
+has 61 seconds, \fI\-\fP means that the last minute of the month has 59 seconds,
+\fI?\fP means the clock is not currently synchronised.) [N]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 9.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 9." 4.2
+.\}
+The number of combined sources. [2]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 10.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 10." 4.2
+.\}
+The estimated standard deviation of the combined offset (in seconds).
+[2.940e\-03]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 11.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 11." 4.2
+.\}
+The remaining offset correction from the previous update (in seconds,
+positive means the system clock is slow of UTC). [\-2.084e\-04]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 12.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 12." 4.2
+.\}
+The total of the network path delays to the reference clock to which
+the local clock is ultimately synchronised (in seconds). [1.534e\-02]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 13.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 13." 4.2
+.\}
+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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 14.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 14." 4.2
+.\}
+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]
+.RE
+.RE
+.sp
+\fBrtc\fP
+.RS 4
+This option logs information about the system\(cqs real\-time clock. An example
+line (which actually appears as a single line in the file) from the \fIrtc.log\fP
+file is shown below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+2015\-07\-22 05:40:50     \-0.037360 1       \-0.037434\(rs
+          \-37.948  12   5  120
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The columns are as follows (the quantities in square brackets are the
+values from the example line above):
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+Date [2015\-07\-22]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+Hour:Minute:Second. Note that the date\-time pair is expressed in UTC, not the
+local time zone. [05:40:50]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+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].
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 4." 4.2
+.\}
+Flag indicating whether the regression has produced valid coefficients.
+(1 for yes, 0 for no). [1]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 5.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 5." 4.2
+.\}
+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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 6.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 6." 4.2
+.\}
+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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 7.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 7." 4.2
+.\}
+The number of measurements used in the regression. [12]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 8.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 8." 4.2
+.\}
+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]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 9.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 9." 4.2
+.\}
+The measurement interval used prior to the measurement being made (in
+seconds). [120]
+.RE
+.RE
+.sp
+\fBrefclocks\fP
+.RS 4
+This option logs the raw and filtered reference clock measurements to a file
+called \fIrefclocks.log\fP. An example line (which actually appears as a single
+line in the file) from the log file is shown below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+2009\-11\-30 14:33:27.000000 PPS2    7 N 1  4.900000e\-07 \-6.741777e\-07  1.000e\-06
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The columns are as follows (the quantities in square brackets are the values
+from the example line above):
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+Date [2009\-11\-30]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+Hour:Minute:Second.Microsecond. Note that the date\-time pair is expressed in
+UTC, not the local time zone. [14:33:27.000000]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+Reference ID of the reference clock from which the measurement came. [PPS2]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 4." 4.2
+.\}
+Sequence number of driver poll within one polling interval for raw samples,
+or \fI\-\fP for filtered samples. [7]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 5.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 5." 4.2
+.\}
+Leap status (\fIN\fP means normal, \fI+\fP means that the last minute of the current
+month has 61 seconds, \fI\-\fP means that the last minute of the month has 59
+seconds). [N]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 6.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 6." 4.2
+.\}
+Flag indicating whether the sample comes from PPS source. (1 for yes,
+0 for no, or \fI\-\fP for filtered sample). [1]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 7.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 7." 4.2
+.\}
+Local clock error measured by reference clock driver, or \fI\-\fP for filtered sample.
+[4.900000e\-07]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 8.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 8." 4.2
+.\}
+Local clock error with applied corrections. Positive indicates that the local
+clock is slow. [\-6.741777e\-07]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 9.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 9." 4.2
+.\}
+Assumed dispersion of the sample. [1.000e\-06]
+.RE
+.RE
+.sp
+\fBtempcomp\fP
+.RS 4
+This option logs the temperature measurements and system rate compensations to
+a file called \fItempcomp.log\fP. An example line (which actually appears as a
+single line in the file) from the log file is shown below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+2015\-04\-19 10:39:48  2.8000e+04  3.6600e\-01
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The columns are as follows (the quantities in square brackets are the values
+from the example line above):
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+Date [2015\-04\-19]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+Hour:Minute:Second. Note that the date\-time pair is expressed in UTC, not the
+local time zone. [10:39:48]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+Temperature read from the sensor. [2.8000e+04]
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 4." 4.2
+.\}
+Applied compensation in ppm, positive means the system clock is running
+faster than it would be without the compensation. [3.6600e\-01]
+.RE
+.RE
+.RE
+.sp
+
+.RS 4
+An example of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+log measurements statistics tracking
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBlogbanner\fP \fIentries\fP
+.RS 4
+A banner is periodically written to the log files enabled by the \fBlog\fP
+directive to indicate the meanings of the columns.
+.sp
+The \fBlogbanner\fP 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.
+.RE
+.sp
+\fBlogchange\fP \fIthreshold\fP
+.RS 4
+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
+\fBsettime\fP command of \fBchronyc\fP are logged.
+.sp
+By default, the threshold is 1 second.
+.sp
+An example of the use is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+logchange 0.1
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+which would cause a syslog message to be generated if a system clock error of over
+0.1 seconds starts to be compensated.
+.RE
+.sp
+\fBlogdir\fP \fIdirectory\fP
+.RS 4
+This directive allows the directory where log files are written to be
+specified.
+.sp
+An example of the use of this directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+logdir /var/log/chrony
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBmailonchange\fP \fIemail\fP \fIthreshold\fP
+.RS 4
+This directive defines an email address to which mail should be sent if
+\fBchronyd\fP applies a correction exceeding a particular threshold to the system
+clock.
+.sp
+An example of the use of this directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+mailonchange root@localhost 0.5
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This would send a mail message to root if a change of more than 0.5 seconds
+were applied to the system clock.
+.sp
+This directive cannot be used when a system call filter is enabled by the \fB\-F\fP
+option as the \fBchronyd\fP process will not be allowed to fork and execute the
+sendmail binary.
+.RE
+.SS "Miscellaneous"
+.sp
+\fBhwtimestamp\fP \fIinterface\fP [\fIoption\fP]...
+.RS 4
+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 \fBxleave\fP option in the \fBserver\fP or the
+\fBpeer\fP directive.
+.sp
+This directive is supported on Linux 3.19 and newer. The NIC must support HW
+timestamping, which can be verified with the \fBethtool \-T\fP command. The list of
+capabilities should include \fISOF_TIMESTAMPING_RAW_HARDWARE\fP,
+\fISOF_TIMESTAMPING_TX_HARDWARE\fP, and \fISOF_TIMESTAMPING_RX_HARDWARE\fP. Receive
+filter \fIHWTSTAMP_FILTER_ALL\fP, or \fIHWTSTAMP_FILTER_NTP_ALL\fP, 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 \fBchronyd\fP is
+running, no other process (e.g. a PTP daemon) should be working with the NIC
+clock.
+.sp
+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 \fImeasurements.log\fP file if enabled by the \fBlog
+measurements\fP directive, and the \fBntpdata\fP report in
+\fBchronyc\fP.
+.sp
+If the specified interface is \fI*\fP, \fBchronyd\fP will try to enable HW timestamping
+on all available interfaces.
+.sp
+The \fBhwtimestamp\fP directive has the following options:
+.sp
+\fBminpoll\fP \fIpoll\fP
+.RS 4
+This option specifies the minimum interval between readings of the NIC clock.
+It\(cqs 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).
+.RE
+.sp
+\fBprecision\fP \fIprecision\fP
+.RS 4
+This option specifies the assumed precision of reading of the NIC clock. The
+default value is 100e\-9 (100 nanoseconds).
+.RE
+.sp
+\fBtxcomp\fP \fIcompensation\fP
+.RS 4
+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.
+.RE
+.sp
+\fBrxcomp\fP \fIcompensation\fP
+.RS 4
+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.
+.RE
+.sp
+\fBnocrossts\fP
+.RS 4
+Some hardware can precisely cross timestamp the NIC clock with the system
+clock. This option disables the use of the cross timestamping.
+.RE
+.sp
+\fBrxfilter\fP \fIfilter\fP
+.RS 4
+This option selects the receive timestamping filter. The \fIfilter\fP can be one of
+the following:
+.sp
+\fIall\fP
+.RS 4
+Enables timestamping of all received packets.
+.RE
+.sp
+\fIntp\fP
+.RS 4
+Enables timestamping of received NTP packets.
+.RE
+.sp
+\fInone\fP
+.RS 4
+Disables timestamping of received packets.
+.RE
+.RE
+.sp
+
+.RS 4
+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 \fInone\fP filter. Forcing timestamping of all packets
+with the \fIall\fP filter when the NIC supports both \fIall\fP and \fIntp\fP filters can be
+useful when packets are received from or on a non\-standard UDP port (e.g.
+specified by the \fBport\fP directive).
+.RE
+.RE
+.sp
+
+.RS 4
+.sp
+Examples of the directive are:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+hwtimestamp eth0
+hwtimestamp eth1 txcomp 300e\-9 rxcomp 645e\-9
+hwtimestamp *
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBinclude\fP \fIpattern\fP
+.RS 4
+The \fBinclude\fP 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.
+.sp
+An example of the directive is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+include @SYSCONFDIR@/chrony.d/*.conf
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBkeyfile\fP \fIfile\fP
+.RS 4
+This directive is used to specify the location of the file containing ID\-key
+pairs for authentication of NTP packets.
+.sp
+The format of the directive is shown in the example below:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+keyfile @SYSCONFDIR@/chrony.keys
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The argument is simply the name of the file containing the ID\-key pairs. The
+format of the file is shown below:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+10 tulip
+11 hyacinth
+20 MD5 ASCII:crocus
+25 SHA1 HEX:1dc764e0791b11fa67efc7ecbc4b0d73f68a070c
+ ...
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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 \fBMD5\fP, which is always supported.
+.sp
+If \fBchronyd\fP was built with enabled support for hashing using a crypto library
+(nettle, nss, or libtomcrypt), the following functions are available: \fBMD5\fP,
+\fBSHA1\fP, \fBSHA256\fP, \fBSHA384\fP, \fBSHA512\fP. Depending on which library and version is
+\fBchronyd\fP using, some or all of the following functions may also be available:
+\fBSHA3\-224\fP, \fBSHA3\-256\fP, \fBSHA3\-384\fP, \fBSHA3\-512\fP, \fBRMD128\fP, \fBRMD160\fP, \fBRMD256\fP,
+\fBRMD320\fP, \fBTIGER\fP, \fBWHIRLPOOL\fP.
+.sp
+The password can be specified as a string of characters not containing white
+space with an optional \fBASCII:\fP prefix, or as a hexadecimal number with the
+\fBHEX:\fP prefix. The maximum length of the line is 2047 characters.
+.sp
+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. \fBchronyd\fP 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.
+.sp
+The \fBkeygen\fP command of \fBchronyc\fP can be used to
+generate random keys for the key file. By default, it generates 160\-bit MD5 or
+SHA1 keys.
+.RE
+.sp
+\fBlock_all\fP
+.RS 4
+The \fBlock_all\fP 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
+\fBmlockall()\fP system call to prevent \fBchronyd\fP from ever being swapped out. This
+should result in lower and more consistent latency. It should not have
+significant impact on performance as \fBchronyd\(cqs\fP memory usage is modest. The
+\fBmlockall(2)\fP man page has more details.
+.RE
+.sp
+\fBpidfile\fP \fIfile\fP
+.RS 4
+\fBchronyd\fP always writes its process ID (PID) to a file, and checks this file on
+startup to see if another \fBchronyd\fP might already be running on the system. By
+default, the file used is \fI@DEFAULT_PID_FILE@\fP. The \fBpidfile\fP directive
+allows the name to be changed, e.g.:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+pidfile /run/chronyd.pid
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBsched_priority\fP \fIpriority\fP
+.RS 4
+On Linux, the \fBsched_priority\fP 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.
+.sp
+On Linux, this directive uses the \fBsched_setscheduler()\fP system call to
+instruct the kernel to use the SCHED_FIFO first\-in, first\-out real\-time
+scheduling policy for \fBchronyd\fP with the specified priority. This means that
+whenever \fBchronyd\fP 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 \fBchronyd\fP resource requirements are modest, but it should
+result in lower and more consistent latency since \fBchronyd\fP 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 \fBsched_setscheduler(2)\fP man page has more
+details.
+.sp
+On macOS, this directive uses the \fBthread_policy_set()\fP kernel call to
+specify real\-time scheduling. As noted for Linux, you should not use this
+directive unless you really need it.
+.RE
+.sp
+\fBuser\fP \fIuser\fP
+.RS 4
+The \fBuser\fP directive sets the name of the system user to which \fBchronyd\fP will
+switch after start in order to drop root privileges.
+.sp
+On Linux, \fBchronyd\fP needs to be compiled with support for the \fBlibcap\fP library.
+On macOS, FreeBSD, NetBSD and Solaris \fBchronyd\fP 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.
+.sp
+The compiled\-in default value is \fI@DEFAULT_USER@\fP.
+.RE
+.SH "EXAMPLES"
+.SS "NTP client with permanent connection to NTP servers"
+.sp
+This section shows how to configure \fBchronyd\fP 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.
+.sp
+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:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Your institution might already operate servers on its network.
+Contact your system administrator to find out.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Your ISP probably has one or more NTP servers available for its
+customers.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+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.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Use public servers from the \c
+.URL "http://www.pool.ntp.org/" "pool.ntp.org" " "
+project.
+.RE
+.sp
+Assuming that your NTP servers are called \fIfoo.example.net\fP, \fIbar.example.net\fP
+and \fIbaz.example.net\fP, your \fIchrony.conf\fP file could contain as a minimum:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+server foo.example.net
+server bar.example.net
+server baz.example.net
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+However, you will probably want to include some of the other directives. The
+\fBdriftfile\fP, \fBmakestep\fP and \fBrtcsync\fP
+might be particularly useful. Also, the \fBiburst\fP option of the
+\fBserver\fP directive is useful to speed up the initial
+synchronisation. The smallest useful configuration file would look something
+like:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+server foo.example.net iburst
+server bar.example.net iburst
+server baz.example.net iburst
+driftfile @CHRONYVARDIR@/drift
+makestep 1.0 3
+rtcsync
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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 \fBpool\fP
+directive instead of multiple \fBserver\fP directives. The configuration file could
+in this case look like:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+pool pool.ntp.org iburst
+driftfile @CHRONYVARDIR@/drift
+makestep 1.0 3
+rtcsync
+.fi
+.if n \{\
+.RE
+.\}
+.SS "NTP client with infrequent connection to NTP servers"
+.sp
+This section shows how to configure \fBchronyd\fP for computers that have
+occasional connections to NTP servers. In this case, you will need some
+additional configuration to tell \fBchronyd\fP when the connection goes up and
+down. This saves the program from continuously trying to poll the servers when
+they are inaccessible.
+.sp
+Again, assuming that your NTP servers are called \fIfoo.example.net\fP,
+\fIbar.example.net\fP and \fIbaz.example.net\fP, your \fIchrony.conf\fP file would now
+contain:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+server foo.example.net offline
+server bar.example.net offline
+server baz.example.net offline
+driftfile @CHRONYVARDIR@/drift
+makestep 1.0 3
+rtcsync
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The \fBoffline\fP keyword indicates that the servers start in an offline state, and
+that they should not be contacted until \fBchronyd\fP receives notification from
+\fBchronyc\fP that the link to the Internet is present. To tell \fBchronyd\fP when to
+start and finish sampling the servers, the \fBonline\fP and
+\fBoffline\fP commands of \fBchronyc\fP need to be used.
+.sp
+To give an example of their use, assuming that \fBpppd\fP is the program being
+used to connect to the Internet and that \fBchronyc\fP has been installed at
+\fI@BINDIR@/chronyc\fP, the script \fI/etc/ppp/ip\-up\fP would include:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+@BINDIR@/chronyc online
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+and the script \fI/etc/ppp/ip\-down\fP would include:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+@BINDIR@/chronyc offline
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+\fBchronyd\fP\(cqs polling of the servers would now only occur whilst the machine is
+actually connected to the Internet.
+.SS "Isolated networks"
+.sp
+This section shows how to configure \fBchronyd\fP for computers that never have
+network conectivity to any computer which ultimately derives its time from a
+reference clock.
+.sp
+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.
+.sp
+The \fBlocal\fP directive enables a local reference mode, which allows
+\fBchronyd\fP to appear synchronised even when it is not.
+.sp
+The rate value in the master\(cqs drift file needs to be set to the average rate
+at which the master gains or loses time. \fBchronyd\fP includes support for this,
+in the form of the \fBmanual\fP directive and the
+\fBsettime\fP command in the \fBchronyc\fP program.
+.sp
+If the master is rebooted, \fBchronyd\fP 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 \(oqmajority\-vote\(cq of selected clients\(aq times; this allows the
+clients to \(oqflywheel\(cq the master while it is rebooting.
+.sp
+The \fBsmoothtime\fP directive is useful when the clocks of the
+clients need to stay close together when the local time is adjusted by the
+\fBsettime\fP command. The smoothing process needs to be
+activated by the \fBsmoothtime activate\fP command when
+the local time is ready to be served. After that point, any adjustments will be
+smoothed out.
+.sp
+A typical configuration file for the master (called \fImaster\fP) might be
+(assuming the clients and the master are in the \fI192.168.165.x\fP subnet):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+initstepslew 1 client1 client3 client6
+driftfile @CHRONYVARDIR@/drift
+local stratum 8
+manual
+allow 192.168.165.0/24
+smoothtime 400 0.01
+rtcsync
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+For the clients that have to resynchronise the master when it restarts,
+the configuration file might be:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+server master iburst
+driftfile @CHRONYVARDIR@/drift
+allow 192.168.165.0/24
+makestep 1.0 3
+rtcsync
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The rest of the clients would be the same, except that the \fBallow\fP directive is
+not required.
+.sp
+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 \fBorphan\fP
+option of the \fBlocal\fP directive enables a special mode where the master is
+selected from multiple computers automatically. They all need to use the same
+\fBlocal\fP 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.
+.sp
+A configuration file for the first server might be (assuming there are three
+servers called \fImaster1\fP, \fImaster2\fP, and \fImaster3\fP):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+initstepslew 1 master2 master3
+server master2
+server master3
+driftfile @CHRONYVARDIR@/drift
+local stratum 8 orphan
+manual
+allow 192.168.165.0/24
+rtcsync
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The other servers would be the same, except the hostnames in the \fBinitstepslew\fP
+and \fBserver\fP directives would be modified to specify the other servers. Their
+clients might be configured to poll all three servers.
+.SS "RTC tracking"
+.sp
+This section considers a computer which has occasional connections to the
+Internet and is turned off between \(oqsessions\(cq. In this case, \fBchronyd\fP relies
+on the computer\(cqs 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 \fBHPET_EMULATE_RTC\fP option in your kernel configuration. Otherwise,
+\fBchronyd\fP will not be able to interact with the RTC device and will give up
+using it.
+.sp
+When the computer is connected to the Internet, \fBchronyd\fP 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\(cqs time error and rate of gaining or losing time.
+.sp
+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.
+.sp
+Whilst the computer is running, \fBchronyd\fP makes measurements of the RTC (via
+the \fI/dev/rtc\fP 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.
+.sp
+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 \fBrtcfile\fP directive has been specified).
+These pieces of information are also saved if the \fBdump\fP
+and \fBwritertc\fP commands respectively are issued
+through \fBchronyc\fP.
+.sp
+When the computer is rebooted, \fBchronyd\fP 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.
+.sp
+The next time the computer goes online, the previous sessions\(aq measurements can
+contribute to the line\-fitting process, which gives a much better estimate of
+the computer\(cqs gain or loss rate.
+.sp
+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 \fBchronyd\fP 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 \fBtrimrtc\fP command in \fBchronyc\fP. Because of this,
+\fBtrimrtc\fP will make sure that a meaningful RTC file is saved after the
+change is completed).
+.sp
+The easiest protection against power failure is to put the \fBdump\fP and
+\fBwritertc\fP commands in the same place as the \fBoffline\fP command is issued to
+take \fBchronyd\fP offline; because \fBchronyd\fP free\-runs between online sessions, no
+parameters will change significantly between going offline from the Internet
+and any power failure.
+.sp
+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). \fBchronyd\fP 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 \fBlog rtc\fP facility in the configuration
+file; this option should not be used if you want your disc to spin down.
+.sp
+To illustrate how a computer might be configured for this case, example
+configuration files are shown.
+.sp
+For the \fIchrony.conf\fP file, the following can be used as an example.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+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
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+\fBpppd\fP is used for connecting to the Internet. This runs two scripts
+\fI/etc/ppp/ip\-up\fP and \fI/etc/ppp/ip\-down\fP when the link goes online and offline
+respectively.
+.sp
+The relevant part of the \fI/etc/ppp/ip\-up\fP file is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+@BINDIR@/chronyc online
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+and the relevant part of the \fI/etc/ppp/ip\-down\fP script is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+@BINDIR@/chronyc \-m offline dump writertc
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+\fBchronyd\fP is started during the boot sequence with the \fB\-r\fP and \fB\-s\fP 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 \fBchronyd\fP\(cqs
+configuration file.
+.sp
+For the system shutdown, \fBchronyd\fP should receive a SIGTERM several seconds
+before the final SIGKILL; the SIGTERM causes the measurement histories and RTC
+information to be saved.
+.SS "Public NTP server"
+.sp
+\fBchronyd\fP can be configured to operate as a public NTP server, e.g. to join the
+.URL "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
+\fBrefclock\fP directive.
+.sp
+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
+\fBratelimit\fP directive. The system timezone database, if it is
+kept up to date and includes the \fIright/UTC\fP timezone, can be used as a
+reliable source to determine when a leap second will be applied to UTC. The
+\fB\-r\fP option with the \fBdumpdir\fP directive shortens the time in which
+\fBchronyd\fP 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).
+.sp
+The configuration file could look like:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+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@
+.fi
+.if n \{\
+.RE
+.\}
+.SH "SEE ALSO"
+.sp
+\fBchronyc(1)\fP, \fBchronyd(8)\fP
+.SH "BUGS"
+.sp
+For instructions on how to report bugs, please visit
+.URL "https://chrony.tuxfamily.org/" "" "."
+.SH "AUTHORS"
+.sp
+chrony was written by Richard Curnow, Miroslav Lichvar, and others.
\ No newline at end of file
diff --git a/chrony_3_3/doc/chronyc.adoc b/chrony_3_3/doc/chronyc.adoc
new file mode 100644
index 0000000..c987907
--- /dev/null
+++ b/chrony_3_3/doc/chronyc.adoc
@@ -0,0 +1,1216 @@
+// This file is part of chrony
+//
+// Copyright (C) Richard P. Curnow  1997-2003
+// Copyright (C) Stephen Wadeley  2016
+// 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.
+
+= chronyc(1)
+:doctype: manpage
+:man manual: User manual
+:man source: chrony @CHRONY_VERSION@
+
+== NAME
+
+chronyc - command-line interface for chrony daemon
+
+== SYNOPSIS
+
+*chronyc* [_OPTION_]... [_COMMAND_]...
+
+== DESCRIPTION
+
+*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.
+
+If no commands are specified on the command line, *chronyc* will expect input
+from the user. The prompt _chronyc>_ will be displayed when it is being run
+from a terminal. If *chronyc*'s input or output are redirected from or to a file,
+the prompt is not shown.
+
+There are two ways *chronyc* can access *chronyd*. One is the Internet
+Protocol (IPv4 or IPv6) and the other is a Unix domain socket, which is
+accessible locally by the root or _chrony_ user. By default, *chronyc* first
+tries to connect to the Unix domain socket. The compiled-in default path is
+_@CHRONYRUNDIR@/chronyd.sock_. If that fails (e.g. because *chronyc* is
+running under a non-root user), it will try to connect to 127.0.0.1 and then
+::1.
+
+Only the following monitoring commands, which do not affect the behaviour of
+*chronyd*, are allowed from the network: *activity*, *manual list*,
+*rtcdata*, *smoothing*, *sources*, *sourcestats*, *tracking*, *waitsync*. The
+set of hosts from which *chronyd* will accept these commands can be configured
+with the <<chrony.conf.adoc#cmdallow,*cmdallow*>> directive in the *chronyd*'s
+configuration file or the <<cmdallow,*cmdallow*>> command in *chronyc*. By
+default, the commands are accepted only from localhost (127.0.0.1 or ::1).
+
+All other commands are allowed only through the Unix domain socket. When sent
+over the network, *chronyd* will respond with a '`Not authorised`' error, even
+if it is from localhost. In chrony versions before 2.2 they were allowed
+from the network if they were authenticated with a password, but that is no
+longer supported.
+
+Having full access to *chronyd* via *chronyc* is more or less equivalent to
+being able to modify the *chronyd*'s configuration file and restart it.
+
+== OPTIONS
+
+*-4*::
+With this option hostnames will be resolved only to IPv4 addresses.
+
+*-6*::
+With this option hostnames will be resolved only to IPv6 addresses.
+
+*-n*::
+This option disables resolving of IP addresses to hostnames, e.g. to avoid slow
+DNS lookups. Long addresses will not be truncated to fit into the column.
+
+*-c*::
+This option enables printing of reports in a comma-separated values (CSV)
+format. IP addresses will not be resolved to hostnames, time will be printed as
+number of seconds since the epoch and values in seconds will not be converted
+to other units.
+
+*-d*::
+This option enables printing of debugging messages if *chronyc* was compiled
+with debugging support.
+
+*-m*::
+Normally, all arguments on the command line are interpreted as one command.
+With this option multiple commands can be specified. Each argument will be
+interpreted as a whole command.
+
+*-h* _host_::
+This option allows the user to specify which host (or comma-separated list of
+addresses) running the *chronyd* program is to be contacted. This allows for
+remote monitoring, without having to connect over SSH to the other host first.
++
+The default is to contact *chronyd* running on the same host where
+*chronyc* is being run.
+
+*-p* _port_::
+This option allows the user to specify the UDP port number which the target
+*chronyd* is using for its monitoring connections. This defaults to 323; there
+would rarely be a need to change this.
+
+*-f* _file_::
+This option is ignored and is provided only for compatibility.
+
+*-a*::
+This option is ignored and is provided only for compatibility.
+
+*-v*::
+With this option *chronyc* displays its version number on the terminal and
+exits.
+
+== COMMANDS
+
+This section describes each of the commands available within the *chronyc*
+program.
+
+=== System clock
+
+[[tracking]]*tracking*::
+The *tracking* command displays parameters about the system's clock
+performance. An example of the output is shown below.
++
+----
+Reference ID    : CB00710F (foo.example.net)
+Stratum         : 3
+Ref time (UTC)  : Fri Jan 27 09:49:17 2017
+System time     : 0.000006523 seconds slow of NTP time
+Last offset     : -0.000006747 seconds
+RMS offset      : 0.000035822 seconds
+Frequency       : 3.225 ppm slow
+Residual freq   : -0.000 ppm
+Skew            : 0.129 ppm
+Root delay      : 0.013639022 seconds
+Root dispersion : 0.001100737 seconds
+Update interval : 64.2 seconds
+Leap status     : Normal
+----
++
+The fields are explained as follows:
++
+*Reference ID*:::
+This is the reference ID and name (or IP address) of the server to which the
+computer is currently synchronised. For IPv4 addresses, the reference ID is
+equal to the address and for IPv6 addresses it is the first 32 bits of the MD5
+sum of the address.
++
+If the reference ID is _7F7F0101_ and there is no name or IP address, it means
+the computer is not synchronised to any external source and that you have the
+_local_ mode operating (via the <<local,*local*>> command in *chronyc*, or the
+<<chrony.conf.adoc#local,*local*>> directive in the configuration file).
++
+The reference ID is printed as a hexadecimal number. Note that in older
+versions it used to be printed in quad-dotted notation and could be confused
+with an IPv4 address.
+*Stratum*:::
+The stratum indicates how many hops away from a computer with an attached
+reference clock we are. Such a computer is a stratum-1 computer, so the
+computer in the example is two hops away (i.e. _foo.example.net_ is a
+stratum-2 and is synchronised from a stratum-1).
+*Ref time*:::
+This is the time (UTC) at which the last measurement from the reference
+source was processed.
+*System time*:::
+In normal operation, *chronyd* by default never steps the system clock, because
+any jump in the time can have adverse consequences for certain application
+programs. Instead, any error in the system clock is corrected by slightly
+speeding up or slowing down the system clock until the error has been removed,
+and then returning to the system clock's normal speed. A consequence of this is
+that there will be a period when the system clock (as read by other programs)
+will be different from *chronyd*'s estimate of the current true time (which it
+reports to NTP clients when it is operating in server mode). The value reported
+on this line is the difference due to this effect.
+*Last offset*:::
+This is the estimated local offset on the last clock update.
+*RMS offset*:::
+This is a long-term average of the offset value.
+*Frequency*:::
+The '`frequency`' is the rate by which the system's clock would be wrong if
+*chronyd* was not correcting it. It is expressed in ppm (parts per million).
+For example, a value of 1 ppm would mean that when the system's clock thinks it
+has advanced 1 second, it has actually advanced by 1.000001 seconds relative to
+true time.
+*Residual freq*:::
+This shows the '`residual frequency`' for the currently selected reference
+source. This reflects any difference between what the measurements from the
+reference source indicate the frequency should be and the frequency currently
+being used.
++
+The reason this is not always zero is that a smoothing procedure is
+applied to the frequency. Each time a measurement from the reference
+source is obtained and a new residual frequency computed, the estimated
+accuracy of this residual is compared with the estimated accuracy (see
+'`skew`' next) of the existing frequency value. A weighted average is
+computed for the new frequency, with weights depending on these accuracies.
+If the measurements from the reference source follow a consistent trend, the
+residual will be driven to zero over time.
+*Skew*:::
+This is the estimated error bound on the frequency.
+*Root delay*:::
+This is the total of the network path delays to the stratum-1 computer from
+which the computer is ultimately synchronised.
+*Root dispersion*:::
+This is the total dispersion accumulated through all the computers back to
+the stratum-1 computer from which the computer is ultimately synchronised.
+Dispersion is due to system clock resolution, statistical measurement
+variations, etc.
++
+An absolute bound on the computer's clock accuracy (assuming the stratum-1
+computer is correct) is given by:
++
+----
+clock_error <= |system_time_offset| + root_dispersion + (0.5 * root_delay)
+----
+*Update interval*:::
+This is the interval between the last two clock updates.
+*Leap status*:::
+This is the leap status, which can be _Normal_, _Insert second_, _Delete
+second_ or _Not synchronised_.
+
+[[makestep]]*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.
++
+The *makestep* command can be used in this situation. There are two forms of
+the command. The first form has no parameters. It tells *chronyd* to cancel any
+remaining correction that was being slewed and jump the system clock by the
+equivalent amount, making it correct immediately.
++
+The second form configures the automatic stepping, similarly to the
+<<chrony.conf.adoc#makestep,*makestep*>> directive. It has two parameters,
+stepping threshold (in seconds) and number of future clock updates for which
+the threshold will be active. This can be used with the <<burst,*burst*>>
+command to quickly make a new measurement and correct the clock by stepping if
+needed, without waiting for *chronyd* to complete the measurement and update
+the clock.
++
+----
+makestep 0.1 1
+burst 1/2
+----
++
+BE WARNED: Certain software will be seriously affected by such jumps in the
+system time. (That is the reason why *chronyd* uses slewing normally.)
+
+[[maxupdateskew]]*maxupdateskew* _skew-in-ppm_::
+This command has the same effect as the
+<<chrony.conf.adoc#maxupdateskew,*maxupdateskew*>> directive in the
+configuration file.
+
+[[waitsync]]*waitsync* [_max-tries_ [_max-correction_ [_max-skew_ [_interval_]]]]::
+The *waitsync* command waits for *chronyd* to synchronise.
++
+Up to four optional arguments can be specified. The first is the maximum number
+of tries before giving up and returning a non-zero error code. When 0 is
+specified, or there are no arguments, the number of tries will not be limited.
++
+The second and third arguments are the maximum allowed remaining correction of
+the system clock and the maximum allowed skew (in ppm) as reported by the
+<<tracking,*tracking*>> command in the *System time* and *Skew* fields. If not
+specified or zero, the value will not be checked.
++
+The fourth argument is the interval specified in seconds in which the check is
+repeated. The interval is 10 seconds by default.
++
+An example is:
++
+----
+waitsync 60 0.01
+----
++
+which will wait up to about 10 minutes (60 times 10 seconds) for *chronyd* to
+synchronise to a source and the remaining correction to be less than 10
+milliseconds.
+
+=== Time sources
+
+[[sources]]*sources* [*-v*]::
+This command displays information about the current time sources that *chronyd*
+is accessing.
++
+The optional argument *-v* can be specified, meaning _verbose_. In this case,
+extra caption lines are shown as a reminder of the meanings of the columns.
++
+----
+210 Number of sources = 3
+MS Name/IP address         Stratum Poll Reach LastRx Last sample
+===============================================================================
+#* GPS0                          0   4   377    11   -479ns[ -621ns] +/-  134ns
+^? foo.example.net               2   6   377    23   -923us[ -924us] +/-   43ms
+^+ bar.example.net               1   6   377    21  -2629us[-2619us] +/-   86ms
+----
++
+The columns are as follows:
++
+*M*:::
+This indicates the mode of the source. _^_ means a server, _=_ means a peer
+and _#_ indicates a locally connected reference clock.
+*S*:::
+This column indicates the state of the source.
+* _*_ indicates the source to which *chronyd* is currently synchronised.
+* _+_ indicates acceptable sources which are combined with the selected
+  source.
+* _-_ indicates acceptable sources which are excluded by the combining
+  algorithm.
+* _?_ indicates sources to which connectivity has been lost or whose packets
+  do not pass all tests. It is also shown at start-up, until at least 3 samples
+  have been gathered from it.
+* _x_ indicates a clock which *chronyd* thinks is a falseticker (i.e. its
+  time is inconsistent with a majority of other sources).
+* _~_ indicates a source whose time appears to have too much variability.
+*Name/IP address*:::
+This shows the name or the IP address of the source, or reference ID for reference
+clocks.
+*Stratum*:::
+This shows the stratum of the source, as reported in its most recently
+received sample. Stratum 1 indicates a computer with a locally attached
+reference clock. A computer that is synchronised to a stratum 1 computer is
+at stratum 2. A computer that is synchronised to a stratum 2 computer is at
+stratum 3, and so on.
+*Poll*:::
+This shows the rate at which the source is being polled, as a base-2
+logarithm of the interval in seconds. Thus, a value of 6 would indicate that
+a measurement is being made every 64 seconds. *chronyd* automatically varies
+the polling rate in response to prevailing conditions.
+*Reach*:::
+This shows the source's reachability register printed as an octal number. The
+register has 8 bits and is updated on every received or missed packet from
+the source. A value of 377 indicates that a valid reply was received for all
+from the last eight transmissions.
+*LastRx*:::
+This column shows how long ago the last sample was received from the source.
+This is normally in seconds. The letters _m_, _h_, _d_ or _y_ indicate
+minutes, hours, days, or years.
+*Last sample*:::
+This column shows the offset between the local clock and the source at the
+last measurement. The number in the square brackets shows the actual measured
+offset. This can be suffixed by _ns_ (indicating nanoseconds), _us_
+(indicating microseconds), _ms_ (indicating milliseconds), or _s_ (indicating
+seconds). The number to the left of the square brackets shows the original
+measurement, adjusted to allow for any slews applied to the local clock
+since. The number following the _+/-_ indicator shows the margin of error in
+the measurement. Positive offsets indicate that the local clock is ahead of
+the source.
+
+[[sourcestats]]*sourcestats* [*-v*]::
+The *sourcestats* command displays information about the drift rate and offset
+estimation process for each of the sources currently being examined by
+*chronyd*.
++
+The optional argument *-v* can be specified, meaning _verbose_. In this case,
+extra caption lines are shown as a reminder of the meanings of the columns.
++
+An example report is:
++
+----
+210 Number of sources = 1
+Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev
+===============================================================================
+foo.example.net            11   5   46m     -0.001      0.045      1us    25us
+----
++
+The columns are as follows:
++
+*Name/IP Address*:::
+This is the name or IP address of the NTP server (or peer) or reference ID of the
+reference clock to which the rest of the line relates.
+*NP*:::
+This is the number of sample points currently being retained for the server.
+The drift rate and current offset are estimated by performing a linear
+regression through these points.
+*NR*:::
+This is the number of runs of residuals having the same sign following the
+last regression. If this number starts to become too small relative to the
+number of samples, it indicates that a straight line is no longer a good fit
+to the data. If the number of runs is too low, *chronyd* discards older
+samples and re-runs the regression until the number of runs becomes
+acceptable.
+*Span*:::
+This is the interval between the oldest and newest samples. If no unit is
+shown the value is in seconds. In the example, the interval is 46 minutes.
+*Frequency*:::
+This is the estimated residual frequency for the server, in parts per
+million. In this case, the computer's clock is estimated to be running 1 part
+in 10^9 slow relative to the server.
+*Freq Skew*:::
+This is the estimated error bounds on *Freq* (again in parts per million).
+*Offset*:::
+This is the estimated offset of the source.
+*Std Dev*:::
+This is the estimated sample standard deviation.
+
+[[reselect]]*reselect*::
+To avoid excessive switching between sources, *chronyd* can stay synchronised
+to a source even when it is not currently the best one among the available
+sources.
++
+The *reselect* command can be used to force *chronyd* to reselect the best
+synchronisation source.
+
+[[reselectdist]]*reselectdist* _distance_::
+The *reselectdist* command sets the reselection distance. It is equivalent to
+the <<chrony.conf.adoc#reselectdist,*reselectdist*>> directive in the
+configuration file.
+
+=== NTP sources
+
+[[activity]]*activity*::
+This command reports the number of servers and peers that are online and
+offline. If the *auto_offline* option is used in specifying some of the servers
+or peers, the *activity* command can be useful for detecting when all of them
+have entered the offline state after the network link has been disconnected.
++
+The report shows the number of servers and peers in 5 states:
++
+*online*:::
+the server or peer is currently online (i.e. assumed by *chronyd* to be reachable)
+*offline*:::
+the server or peer is currently offline (i.e. assumed by *chronyd* to be
+unreachable, and no measurements from it will be attempted.)
+*burst_online*:::
+a burst command has been initiated for the server or peer and is being
+performed; after the burst is complete, the server or peer will be returned to
+the online state.
+*burst_offline*:::
+a burst command has been initiated for the server or peer and is being
+performed; after the burst is complete, the server or peer will be returned to
+the offline state.
+*unresolved*:::
+the name of the server or peer was not resolved to an address yet; this source is
+not visible in the *sources* and *sourcestats* reports.
+
+[[ntpdata]]*ntpdata* [_address_]::
+The *ntpdata* command displays the last valid measurement and other
+NTP-specific information about the specified NTP source, or all NTP sources if
+no address was specified. An example of the output is shown below.
++
+----
+Remote address  : 203.0.113.15 (CB00710F)
+Remote port     : 123
+Local address   : 203.0.113.74 (CB00714A)
+Leap status     : Normal
+Version         : 4
+Mode            : Server
+Stratum         : 1
+Poll interval   : 10 (1024 seconds)
+Precision       : -24 (0.000000060 seconds)
+Root delay      : 0.000015 seconds
+Root dispersion : 0.000015 seconds
+Reference ID    : 47505300 (GPS)
+Reference time  : Fri Nov 25 15:22:12 2016
+Offset          : -0.000060878 seconds
+Peer delay      : 0.000175634 seconds
+Peer dispersion : 0.000000681 seconds
+Response time   : 0.000053050 seconds
+Jitter asymmetry: +0.00
+NTP tests       : 111 111 1111
+Interleaved     : No
+Authenticated   : No
+TX timestamping : Kernel
+RX timestamping : Kernel
+Total TX        : 24
+Total RX        : 24
+Total valid RX  : 24
+----
++
+The fields are explained as follows:
++
+*Remote address*:::
+The IP address of the NTP server or peer, and the corresponding reference ID.
+*Remote port*:::
+The UDP port number to which the request was sent. The standard NTP port is
+123.
+*Local address*:::
+The local IP address which received the response, and the corresponding
+reference ID.
+*Leap status*:::
+*Version*:::
+*Mode*:::
+*Stratum*:::
+*Poll interval*:::
+*Precision*:::
+*Root delay*:::
+*Root dispersion*:::
+*Reference ID*:::
+*Reference time*:::
+The NTP values from the last valid response.
+*Offset*:::
+*Peer delay*:::
+*Peer dispersion*:::
+The measured values.
+*Response time*:::
+The time the server or peer spent in processing of the request and waiting
+before sending the response.
+*Jitter asymmetry*:::
+The estimated asymmetry of network jitter on the path to the source. 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.
+*NTP tests*:::
+Results of RFC 5905 tests 1 through 3, 5 through 7, and tests for maximum
+delay, delay ratio, delay dev ratio, and synchronisation loop.
+*Interleaved*:::
+This shows if the response was in the interleaved mode.
+*Authenticated*:::
+This shows if the response was authenticated.
+*TX timestamping*:::
+The source of the local transmit timestamp. Valid values are _Daemon_,
+_Kernel_, and _Hardware_.
+*RX timestamping*:::
+The source of the local receive timestamp.
+*Total TX*:::
+The number of packets sent to the source.
+*Total RX*:::
+The number of all packets received from the source.
+*Total valid RX*:::
+The number of valid packets received from the source.
+
+[[add_peer]]*add peer* _address_ [_option_]...::
+The *add peer* command allows a new NTP peer to be added whilst
+*chronyd* is running.
++
+Following the words *add peer*, the syntax of the following
+parameters and options is similar to that for the
+<<chrony.conf.adoc#peer,*peer*>> directive in the configuration file.
+The following peer options can be set in the command: *port*, *minpoll*,
+*maxpoll*, *presend*, *maxdelayratio*, *maxdelay*, *key*.
++
+An example of using this command is shown below.
++
+----
+add peer foo.example.net minpoll 6 maxpoll 10 key 25
+----
+
+[[add_server]]*add server* _address_ [_option_]...::
+The *add server* command allows a new NTP server to be added whilst
+*chronyd* is running.
++
+Following the words *add server*, the syntax of the following parameters and
+options is similar to that for the <<chrony.conf.adoc#server,*server*>>
+directive in the configuration file.
+The following server options can be set in the command: *port*, *minpoll*,
+*maxpoll*, *presend*, *maxdelayratio*, *maxdelay*, *key*.
++
+An example of using this command is shown below:
++
+----
+add server foo.example.net minpoll 6 maxpoll 10 key 25
+----
+
+[[delete]]*delete* _address_::
+The *delete* command allows an NTP server or peer to be removed
+from the current set of sources.
+
+[[burst]]
+*burst* _good_/_max_ [_mask_/_masked-address_]::
+*burst* _good_/_max_ [_masked-address_/_masked-bits_]::
+*burst* _good_/_max_ [_address_]::
+The *burst* command tells *chronyd* to make a set of measurements to each of
+its NTP sources over a short duration (rather than the usual periodic
+measurements that it makes). After such a burst, *chronyd* will revert to the
+previous state for each source. This might be either online, if the source was
+being periodically measured in the normal way, or offline, if the source had
+been indicated as being offline. (A source can be switched between the online
+and offline states with the <<online,*online*>> and <<offline,*offline*>>
+commands.)
++
+The _mask_ and _masked-address_ arguments are optional, in which case *chronyd*
+will initiate a burst for all of its currently defined sources.
++
+The arguments have the following meaning and format:
++
+_good_:::
+This defines the number of good measurements that *chronyd* will want to
+obtain from each source. A measurement is good if it passes certain tests,
+for example, the round trip time to the source must be acceptable. (This
+allows *chronyd* to reject measurements that are likely to be bogus.)
+_max_:::
+This defines the maximum number of measurements that *chronyd* will attempt
+to make, even if the required number of good measurements has not been
+obtained.
+_mask_:::
+This is an IP address with which the IP address of each of *chronyd*'s
+sources is to be masked.
+_masked-address_:::
+This is an IP address. If the masked IP address of a source matches this
+value then the burst command is applied to that source.
+_masked-bits_:::
+This can be used with _masked-address_ for CIDR notation, which is a shorter
+alternative to the form with mask.
+_address_:::
+This is an IP address or a hostname. The burst command is applied only to
+that source.
+::
++
+If no _mask_ or _masked-address_ arguments are provided, every source will be
+matched.
++
+An example of the two-argument form of the command is:
++
+----
+burst 2/10
+----
++
+This will cause *chronyd* to attempt to get two good measurements from each
+source, stopping after two have been obtained, but in no event will it try more
+than ten probes to the source.
++
+Examples of the four-argument form of the command are:
++
+----
+burst 2/10 255.255.0.0/1.2.0.0
+burst 2/10 2001:db8:789a::/48
+----
++
+In the first case, the two out of ten sampling will only be applied to sources
+whose IPv4 addresses are of the form _1.2.x.y_, where _x_ and _y_ are
+arbitrary. In the second case, the sampling will be applied to sources whose
+IPv6 addresses have first 48 bits equal to _2001:db8:789a_.
++
+Example of the three-argument form of the command is:
++
+----
+burst 2/10 foo.example.net
+----
+
+[[maxdelay]]*maxdelay* _address_ _delay_::
+This allows the *maxdelay* option for one of the sources to be modified, in the
+same way as specifying the *maxdelay* option for the
+<<chrony.conf.adoc#server,*server*>> directive in the configuration file.
+
+[[maxdelaydevratio]]*maxdelaydevratio* _address_ _ratio_::
+This allows the *maxdelaydevratio* option for one of the sources to be
+modified, in the same way as specifying the *maxdelaydevratio* option for the
+<<chrony.conf.adoc#server,*server*>> directive in the configuration file.
+
+[[maxdelayratio]]*maxdelayratio* _address_ _ratio_::
+This allows the *maxdelayratio* option for one of the sources to be modified,
+in the same way as specifying the *maxdelayratio* option for the
+<<chrony.conf.adoc#server,*server*>> directive in the configuration file.
+
+[[maxpoll]]*maxpoll* _address_ _maxpoll_::
+The *maxpoll* command is used to modify the maximum polling interval for one of
+the current set of sources. It is equivalent to the *maxpoll* option in the
+<<chrony.conf.adoc#server,*server*>> directive in the configuration file.
++
+Note that the new maximum polling interval only takes effect after the next
+measurement has been made.
+
+[[minpoll]]*minpoll* _address_ _minpoll_::
+The *minpoll* command is used to modify the minimum polling interval for one of
+the current set of sources. It is equivalent to the *minpoll* option in the
+<<chrony.conf.adoc#server,*server*>> directive in the configuration file.
++
+Note that the new minimum polling interval only takes effect after the next
+measurement has been made.
+
+[[minstratum]]*minstratum* _address_ _minstratum_::
+The *minstratum* command is used to modify the minimum stratum for one of the
+current set of sources. It is equivalent to the *minstratum* option in the
+<<chrony.conf.adoc#server,*server*>> directive in the configuration file.
+
+[[offline]]
+*offline* [_address_]::
+*offline* [_masked-address_/_masked-bits_]::
+*offline* [_mask_/_masked-address_]::
+The *offline* command is used to warn *chronyd* that the network connection to
+a particular host or hosts is about to be lost, e.g. on computers with
+intermittent connection to their time sources.
++
+Another case where *offline* could be used is where a computer serves time to a
+local group of computers, and has a permanent connection to true time servers
+outside the organisation. However, the external connection is heavily loaded at
+certain times of the day and the measurements obtained are less reliable at
+those times. In this case, it is probably most useful to determine the
+gain or loss rate during the quiet periods and let the whole network coast through
+the loaded periods. The *offline* and *online* commands can be used to achieve
+this.
++
+There are four forms of the *offline* command. The first form is a wildcard,
+meaning all sources. The second form allows an IP address mask and a masked
+address to be specified. The third form uses CIDR notation. The fourth form
+uses an IP address or a hostname. These forms are illustrated below.
++
+----
+offline
+offline 255.255.255.0/1.2.3.0
+offline 2001:db8:789a::/48
+offline foo.example.net
+----
++
+The second form means that the *offline* command is to be applied to any source
+whose IPv4 address is in the _1.2.3_ subnet. (The host's address is logically
+and-ed with the mask, and if the result matches the _masked-address_ the host
+is processed.) The third form means that the command is to be applied to all
+sources whose IPv6 addresses have their first 48 bits equal to _2001:db8:789a_. The
+fourth form means that the command is to be applied only to that one source.
++
+The wildcard form of the address is equivalent to:
++
+----
+offline 0.0.0.0/0.0.0.0
+offline ::/0
+----
+
+[[online]]
+*online* [_address_]::
+*online* [_masked-address_/_masked-bits_]::
+*online* [_mask_/_masked-address_]::
+The *online* command is opposite in function to the <<offline,*offline*>>
+command. It is used to advise *chronyd* that network connectivity to a
+particular source or sources has been restored.
++
+The syntax is identical to that of the <<offline,*offline*>> command.
+
+[[polltarget]]*polltarget* _address_ _polltarget_::
+The *polltarget* command is used to modify the poll target for one of the
+current set of sources. It is equivalent to the *polltarget* option in the
+<<chrony.conf.adoc#server,*server*>> directive in the configuration file.
+
+[[refresh]]*refresh*::
+The *refresh* command can be used to force *chronyd* to resolve the names of
+configured sources to IP addresses again, e.g. after suspending and resuming
+the machine in a different network.
++
+Sources that stop responding will be replaced with newly resolved addresses
+automatically after 8 polling intervals, but this command can still be useful
+to replace them immediately and not wait until they are marked as unreachable.
+
+=== Manual time input
+
+[[manual]]
+*manual* *on*::
+*manual* *off*::
+*manual* *delete* _index_::
+*manual* *list*::
+*manual* *reset*::
+The manual command enables and disables use of the <<settime,*settime*>>
+command, and is used to modify the behaviour of the manual clock driver.
++
+The *on* form of the command enables use of the *settime* command.
++
+The *off* form of the command disables use of the *settime* command.
++
+The *list* form of the command lists all the samples currently stored in
+*chronyd*. The output is illustrated below.
++
+----
+210 n_samples = 1
+#    Date  Time(UTC)    Slewed   Original   Residual
+====================================================
+ 0 27Jan99 22:09:20       0.00       0.97       0.00
+----
++
+The columns are as as follows:
++
+. The sample index (used for the *manual delete* command).
+. The date and time of the sample.
+. The system clock error when the timestamp was entered, adjusted to allow
+  for changes made to the system clock since.
+. The system clock error when the timestamp was entered, as it originally was
+  (without allowing for changes to the system clock since).
+. The regression residual at this point, in seconds. This allows '`outliers`'
+  to be easily spotted, so that they can be deleted using the *manual delete*
+  command.
+::
++
+The *delete* form of the command deletes a single sample. The parameter is the
+index of the sample, as shown in the first column of the output from *manual
+list*. Following deletion of the data point, the current error and drift rate
+are re-estimated from the remaining data points and the system clock trimmed if
+necessary. This option is intended to allow '`outliers`' to be discarded, i.e.
+samples where the administrator realises they have entered a very poor
+timestamp.
++
+The *reset* form of the command deletes all samples at once. The system clock
+is left running as it was before the command was entered.
+
+[[settime]]*settime* _time_::
+The *settime* command allows the current time to be entered manually, if this
+option has been configured into *chronyd*. (It can be configured either with
+the <<chrony.conf.adoc#manual,*manual*>> directive in the configuration file,
+or with the <<manual,*manual*>> command of *chronyc*.)
++
+It should be noted that the computer's sense of time will only be as accurate
+as the reference you use for providing this input (e.g. your watch), as well as
+how well you can time the press of the return key.
++
+Providing your computer's time zone is set up properly, you will be able to
+enter a local time (rather than UTC).
++
+The response to a successful *settime* command indicates the amount that the
+computer's clock was wrong. It should be apparent from this if you have entered
+the time wrongly, e.g. with the wrong time zone.
++
+The rate of drift of the system clock is estimated by a regression process
+using the entered measurement and all previous measurements entered during the
+present run of *chronyd*. However, the entered measurement is used for
+adjusting the current clock offset (rather than the estimated intercept from
+the regression, which is ignored). Contrast what happens with the
+<<manual,*manual delete*>> command, where the intercept is used to set the
+current offset (since there is no measurement that has just been entered in
+that case).
++
+The time is parsed by the public domain _getdate_ algorithm. Consequently, you
+can only specify time to the nearest second.
++
+Examples of inputs that are valid are shown below:
++
+----
+settime 16:30
+settime 16:30:05
+settime Nov 21, 2015 16:30:05
+----
++
+For a full description of getdate, see the getdate documentation
+(bundled, for example, with the source for GNU tar).
+
+=== NTP access
+
+[[accheck]]*accheck* _address_::
+This command allows you to check whether client NTP access is allowed from a
+particular host.
++
+Examples of use, showing a named host and a numeric IP address, are as follows:
++
+----
+accheck foo.example.net
+accheck 1.2.3.4
+accheck 2001:db8::1
+----
++
+This command can be used to examine the effect of a series of *allow*, *allow
+all*, *deny*, and *deny all* commands specified either via *chronyc*, or in
+*chronyd*'s configuration file.
+
+[[clients]]*clients*::
+This command shows a list of clients that have accessed the server, through
+either the NTP or command ports. It does not include accesses over
+the Unix domain command socket. There are no arguments.
++
+An example of the output is:
++
+----
+Hostname                      NTP   Drop Int IntL Last     Cmd   Drop Int  Last
+===============================================================================
+localhost                       2      0   2   -   133      15      0  -1     7
+foo.example.net                12      0   6   -    23       0      0   -     -
+----
++
+Each row shows the data for a single host. Only hosts that have passed the host
+access checks (set with the <<allow,*allow*>>, <<deny,*deny*>>,
+<<cmdallow,*cmdallow*>> and <<cmddeny,*cmddeny*>> commands or configuration
+file directives) are logged. The intervals are displayed as a power of 2 in
+seconds.
++
+The columns are as follows:
++
+. The hostname of the client.
+. The number of NTP packets received from the client.
+. The number of NTP packets dropped to limit the response rate.
+. The average interval between NTP packets.
+. The average interval between NTP packets after limiting the response rate.
+. Time since the last NTP packet was received
+. The number of command packets received from the client.
+. The number of command packets dropped to limit the response rate.
+. The average interval between command packets.
+. Time since the last command packet was received.
+
+[[serverstats]]*serverstats*::
+The *serverstats* command displays how many valid NTP and command requests
+*chronyd* as a server received from clients, how many of them were dropped to
+limit the response rate as configured by the
+<<chrony.conf.adoc#ratelimit,*ratelimit*>> and
+<<chrony.conf.adoc#cmdratelimit,*cmdratelimit*>> directives, and how many
+client log records were dropped due to the memory limit configured by the
+<<chrony.conf.adoc#clientloglimit,*clientloglimit*>> directive. An example of
+the output is shown below.
++
+----
+NTP packets received       : 1598
+NTP packets dropped        : 8
+Command packets received   : 19
+Command packets dropped    : 0
+Client log records dropped : 0
+----
+
+[[allow]]*allow* [*all*] [_subnet_]::
+The effect of the allow command is identical to the
+<<chrony.conf.adoc#allow,*allow*>> directive in the configuration file.
++
+The syntax is illustrated in the following examples:
++
+----
+allow foo.example.net
+allow all 1.2
+allow 3.4.5
+allow 6.7.8/22
+allow 6.7.8.9/22
+allow 2001:db8:789a::/48
+allow 0/0
+allow ::/0
+allow
+allow all
+----
+
+[[deny]]*deny* [*all*] [_subnet_]::
+The effect of the allow command is identical to the
+<<chrony.conf.adoc#deny,*deny*>> directive in the configuration file.
++
+The syntax is illustrated in the following examples:
++
+----
+deny foo.example.net
+deny all 1.2
+deny 3.4.5
+deny 6.7.8/22
+deny 6.7.8.9/22
+deny 2001:db8:789a::/48
+deny 0/0
+deny ::/0
+deny
+deny all
+----
+
+[[local]]
+*local* [_option_]...::
+*local* *off*::
+The *local* command allows *chronyd* to be told that it is to appear as a
+reference source, even if it is not itself properly synchronised to an external
+source. (This can be used on isolated networks, to allow one computer to be a
+master time server with the other computers slaving to it.)
++
+The first form enables the local reference mode on the host. The syntax is
+identical to the <<chrony.conf.adoc#local,*local*>> directive in the
+configuration file.
++
+The second form disables the local reference mode.
+
+[[smoothing]]*smoothing*::
+The *smoothing* command displays the current state of the NTP server time
+smoothing, which can be enabled with the
+<<chrony.conf.adoc#smoothtime,*smoothtime*>> directive. An example of the
+output is shown below.
++
+----
+Active         : Yes
+Offset         : +1.000268817 seconds
+Frequency      : -0.142859 ppm
+Wander         : -0.010000 ppm per second
+Last update    : 17.8 seconds ago
+Remaining time : 19988.4 seconds
+----
++
+The fields are explained as follows:
++
+*Active*:::
+This shows if the server time smoothing is currently active. Possible values
+are _Yes_ and _No_. If the *leaponly* option is included in the *smoothtime*
+directive, _(leap second only)_ will be shown on the line.
+*Offset*:::
+This is the current offset applied to the time sent to NTP clients. Positive
+value means the clients are getting time that's ahead of true time.
+*Frequency*:::
+The current frequency offset of the served time. Negative value means the
+time observed by clients is running slower than true time.
+*Wander*:::
+The current frequency wander of the served time. Negative value means the
+time observed by clients is slowing down.
+*Last update*:::
+This field shows how long ago the time smoothing process was updated, e.g.
+*chronyd* accumulated a new measurement.
+*Remaining time*:::
+The time it would take for the smoothing process to get to zero offset and
+frequency if there were no more updates.
+
+[[smoothtime]]
+*smoothtime* *activate*::
+*smoothtime* *reset*::
+The *smoothtime* command can be used to activate or reset the server time
+smoothing process if it is configured with the
+<<chrony.conf.adoc#smoothtime,*smoothtime*>> directive.
+
+=== Monitoring access
+
+[[cmdaccheck]]*cmdaccheck* _address_::
+This command is similar to the <<accheck,*accheck*>> command, except that it is
+used to check whether monitoring access is permitted from a named host.
++
+Examples of use are as follows:
++
+----
+cmdaccheck foo.example.net
+cmdaccheck 1.2.3.4
+cmdaccheck 2001:db8::1
+----
+
+[[cmdallow]]*cmdallow* [*all*] [_subnet_]::
+This is similar to the <<allow,*allow*>> command, except that it is used to
+allow particular hosts or subnets to use *chronyc* to monitor with *chronyd* on
+the current host.
+
+[[cmddeny]]*cmddeny* [*all*] [_subnet_]::
+This is similar to the <<deny,*deny*>> command, except that it is used to allow
+particular hosts or subnets to use *chronyc* to monitor *chronyd* on the
+current host.
+
+=== Real-time clock (RTC)
+
+[[rtcdata]]*rtcdata*::
+The *rtcdata* command displays the current RTC parameters.
++
+An example output is shown below.
++
+----
+RTC ref time (GMT) : Sat May 30 07:25:56 2015
+Number of samples  : 10
+Number of runs     : 5
+Sample span period :  549
+RTC is fast by     :    -1.632736 seconds
+RTC gains time at  :  -107.623 ppm
+----
++
+The fields have the following meaning:
++
+*RTC ref time (GMT)*:::
+This is the RTC reading the last time its error was measured.
+*Number of samples*:::
+This is the number of previous measurements being used to determine the RTC
+gain or loss rate.
+*Number of runs*:::
+This is the number of runs of residuals of the same sign following the
+regression fit for (RTC error) versus (RTC time). A value which is small
+indicates that the measurements are not well approximated by a linear model,
+and that the algorithm will tend to delete the older measurements to improve
+the fit.
+*Sample span period*:::
+This is the period that the measurements span (from the oldest to the
+newest). Without a unit the value is in seconds; suffixes _m_ for minutes,
+_h_ for hours, _d_ for days or _y_ for years can be used.
+*RTC is fast by*:::
+This is the estimate of how many seconds fast the RTC when it thought
+the time was at the reference time (above). If this value is large, you
+might (or might not) want to use the <<trimrtc,*trimrtc*>> command to bring the
+RTC into line with the system clock. (Note, a large error will not affect
+*chronyd*'s operation, unless it becomes so big as to start causing rounding
+errors.)
+*RTC gains time at*:::
+This is the amount of time gained (positive) or lost (negative) by the real
+time clock for each second that it ticks. It is measured in parts per
+million. So if the value shown was +1, suppose the RTC was exactly right when
+it crosses a particular second boundary. Then it would be 1 microsecond fast
+when it crosses its next second boundary.
+
+[[trimrtc]]*trimrtc*::
+The *trimrtc* command is used to correct the system's real-time clock (RTC) to
+the main system clock. It has no effect if the error between the two clocks is
+currently estimated at less than a second.
++
+The command takes no arguments. It performs the following steps (if the RTC is
+more than 1 second away from the system clock):
++
+. Remember the currently estimated gain or loss rate of the RTC and flush the
+  previous measurements.
+. Step the real-time clock to bring it within a second of the system clock.
+. Make several measurements to accurately determine the new offset between
+  the RTC and the system clock (i.e. the remaining fraction of a second
+  error).
+. Save the RTC parameters to the RTC file (specified with the
+  <<chrony.conf.adoc#rtcfile,*rtcfile*>> directive in the configuration file).
+::
++
+The last step is done as a precaution against the computer suffering a power
+failure before either the daemon exits or the <<writertc,*writertc*>> command
+is issued.
++
+*chronyd* will still work perfectly well both whilst operating and across
+machine reboots even if the *trimrtc* command is never used (and the RTC is
+allowed to drift away from true time). The *trimrtc* command is provided as a
+method by which it can be corrected, in a manner compatible with *chronyd*
+using it to maintain accurate time across machine reboots.
++
+The *trimrtc* command can be executed automatically by *chronyd* with the
+<<chrony.conf.adoc#rtcautotrim,*rtcautotrim*>> directive in the configuration
+file.
+
+[[writertc]]*writertc*::
+The *writertc* command writes the currently estimated error and gain or loss rate
+parameters for the RTC to the RTC file (specified with the
+<<chrony.conf.adoc#rtcfile,*rtcfile*>> directive). This information is also
+written automatically when *chronyd* is killed (by the SIGHUP, SIGINT, SIGQUIT
+or SIGTERM signals) or when the <<trimrtc,*trimrtc*>> command is issued.
+
+=== Other daemon commands
+
+[[cyclelogs]]*cyclelogs*::
+The *cyclelogs* command causes all of *chronyd*'s open log files to be closed
+and re-opened. This allows them to be renamed so that they can be periodically
+purged. An example of how to do this is shown below.
++
+----
+# mv /var/log/chrony/measurements.log /var/log/chrony/measurements1.log
+# chronyc cyclelogs
+# ls -l /var/log/chrony
+-rw-r--r--   1 root     root            0 Jun  8 18:17 measurements.log
+-rw-r--r--   1 root     root        12345 Jun  8 18:17 measurements1.log
+# rm -f measurements1.log
+----
+
+[[dump]]*dump*::
+The *dump* command causes *chronyd* to write its current history of
+measurements for each of its sources to dump files in the directory specified
+in the configuration file by the <<chrony.conf.adoc#dumpdir,*dumpdir*>>
+directive. Note that *chronyd* does this automatically when it exits. This
+command is mainly useful for inspection of the history whilst *chronyd* is
+running.
+
+[[rekey]]*rekey*::
+The *rekey* command causes *chronyd* to re-read the key file specified in the
+configuration file by the <<chrony.conf.adoc#keyfile,*keyfile*>> directive.
+
+[[rekey]]*shutdown*::
+The *shutdown* command causes *chronyd* to exit. This is equivalent to sending
+the process the SIGTERM signal.
+
+=== Client commands
+
+[[dns]]*dns* _option_::
+The *dns* command configures how hostnames and IP addresses are resolved in
+*chronyc*. IP addresses can be resolved to hostnames when printing results of
+<<sources,*sources*>>, <<sourcestats,*sourcestats*>>, <<tracking,*tracking*>>
+and <<clients,*clients*>> commands. Hostnames are resolved in commands that
+take an address as argument.
++
+There are five options:
++
+*dns -n*:::
+Disables resolving IP addresses to hostnames. Raw IP addresses will be
+displayed.
+*dns +n*:::
+Enables resolving IP addresses to hostnames. This is the default unless
+*chronyc* was started with *-n* option.
+*dns -4*:::
+Resolves hostnames only to IPv4 addresses.
+*dns -6*:::
+Resolves hostnames only to IPv6 addresses.
+*dns -46*:::
+Resolves hostnames to both address families. This is the default behaviour
+unless *chronyc* was started with the *-4* or *-6* option.
+
+[[timeout]]*timeout* _timeout_::
+The *timeout* command sets the initial timeout for *chronyc* requests in
+milliseconds. If no response is received from *chronyd*, the timeout is doubled
+and the request is resent. The maximum number of retries is configured with the
+<<retries,*retries*>> command.
++
+By default, the timeout is 1000 milliseconds.
+
+[[retries]]*retries* _retries_::
+The *retries* command sets the maximum number of retries for *chronyc* requests
+before giving up. The response timeout is controlled by the
+<<timeout,*timeout*>> command.
++
+The default is 2.
+
+[[keygen]]*keygen* [_id_ [_type_ [_bits_]]]::
+The *keygen* command generates a key that can be added to the
+key file (specified with the <<chrony.conf.adoc#keyfile,*keyfile*>> directive)
+to allow NTP authentication between server and client, or peers. The key is
+generated from the _/dev/urandom_ device and it is printed to standard output.
++
+The command has three optional arguments. The first argument is the key number
+(by default 1), which will be specified with the *key* option of the *server*
+or *peer* directives in the configuration file. The second argument is the hash
+function (by default SHA1 or MD5 if SHA1 is not available) and the third
+argument is the number of bits the key should have, between 80 and 4096 bits
+(by default 160 bits).
++
+An example is:
++
+----
+keygen 73 SHA1 256
+----
++
+which generates a 256-bit SHA1 key with number 73. The printed line should
+then be securely transferred and added to the key files on both server and
+client, or peers.
+
+[[exit]]*exit*::
+[[quit]]*quit*::
+The *exit* and *quit* commands exit from *chronyc* and return the user to the shell.
+
+[[help]]*help*::
+The *help* command displays a summary of the commands and their arguments.
+
+== SEE ALSO
+
+<<chrony.conf.adoc#,*chrony.conf(5)*>>, <<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/chrony_3_3/doc/chronyc.man.in b/chrony_3_3/doc/chronyc.man.in
new file mode 100644
index 0000000..75999a5
--- /dev/null
+++ b/chrony_3_3/doc/chronyc.man.in
@@ -0,0 +1,1905 @@
+'\" t
+.\"     Title: chronyc
+.\"    Author: [see the "AUTHORS" section]
+.\" Generator: Asciidoctor 1.5.6.1
+.\"      Date: 2018-04-04
+.\"    Manual: User manual
+.\"    Source: chrony @CHRONY_VERSION@
+.\"  Language: English
+.\"
+.TH "CHRONYC" "1" "2018-04-04" "chrony @CHRONY_VERSION@" "User manual"
+.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"
+chronyc \- command\-line interface for chrony daemon
+.SH "SYNOPSIS"
+.sp
+\fBchronyc\fP [\fIOPTION\fP]... [\fICOMMAND\fP]...
+.SH "DESCRIPTION"
+.sp
+\fBchronyc\fP is a command\-line interface program which can be used to monitor
+\fBchronyd\fP\(cqs performance and to change various operating parameters whilst it is
+running.
+.sp
+If no commands are specified on the command line, \fBchronyc\fP will expect input
+from the user. The prompt \fIchronyc>\fP will be displayed when it is being run
+from a terminal. If \fBchronyc\fP\(cqs input or output are redirected from or to a file,
+the prompt is not shown.
+.sp
+There are two ways \fBchronyc\fP can access \fBchronyd\fP. One is the Internet
+Protocol (IPv4 or IPv6) and the other is a Unix domain socket, which is
+accessible locally by the root or \fIchrony\fP user. By default, \fBchronyc\fP first
+tries to connect to the Unix domain socket. The compiled\-in default path is
+\fI@CHRONYRUNDIR@/chronyd.sock\fP. If that fails (e.g. because \fBchronyc\fP is
+running under a non\-root user), it will try to connect to 127.0.0.1 and then
+::1.
+.sp
+Only the following monitoring commands, which do not affect the behaviour of
+\fBchronyd\fP, are allowed from the network: \fBactivity\fP, \fBmanual list\fP,
+\fBrtcdata\fP, \fBsmoothing\fP, \fBsources\fP, \fBsourcestats\fP, \fBtracking\fP, \fBwaitsync\fP. The
+set of hosts from which \fBchronyd\fP will accept these commands can be configured
+with the \fBcmdallow\fP directive in the \fBchronyd\fP\(cqs
+configuration file or the \fBcmdallow\fP command in \fBchronyc\fP. By
+default, the commands are accepted only from localhost (127.0.0.1 or ::1).
+.sp
+All other commands are allowed only through the Unix domain socket. When sent
+over the network, \fBchronyd\fP will respond with a \(oqNot authorised\(cq error, even
+if it is from localhost. In chrony versions before 2.2 they were allowed
+from the network if they were authenticated with a password, but that is no
+longer supported.
+.sp
+Having full access to \fBchronyd\fP via \fBchronyc\fP is more or less equivalent to
+being able to modify the \fBchronyd\fP\(cqs configuration file and restart it.
+.SH "OPTIONS"
+.sp
+\fB\-4\fP
+.RS 4
+With this option hostnames will be resolved only to IPv4 addresses.
+.RE
+.sp
+\fB\-6\fP
+.RS 4
+With this option hostnames will be resolved only to IPv6 addresses.
+.RE
+.sp
+\fB\-n\fP
+.RS 4
+This option disables resolving of IP addresses to hostnames, e.g. to avoid slow
+DNS lookups. Long addresses will not be truncated to fit into the column.
+.RE
+.sp
+\fB\-c\fP
+.RS 4
+This option enables printing of reports in a comma\-separated values (CSV)
+format. IP addresses will not be resolved to hostnames, time will be printed as
+number of seconds since the epoch and values in seconds will not be converted
+to other units.
+.RE
+.sp
+\fB\-d\fP
+.RS 4
+This option enables printing of debugging messages if \fBchronyc\fP was compiled
+with debugging support.
+.RE
+.sp
+\fB\-m\fP
+.RS 4
+Normally, all arguments on the command line are interpreted as one command.
+With this option multiple commands can be specified. Each argument will be
+interpreted as a whole command.
+.RE
+.sp
+\fB\-h\fP \fIhost\fP
+.RS 4
+This option allows the user to specify which host (or comma\-separated list of
+addresses) running the \fBchronyd\fP program is to be contacted. This allows for
+remote monitoring, without having to connect over SSH to the other host first.
+.sp
+The default is to contact \fBchronyd\fP running on the same host where
+\fBchronyc\fP is being run.
+.RE
+.sp
+\fB\-p\fP \fIport\fP
+.RS 4
+This option allows the user to specify the UDP port number which the target
+\fBchronyd\fP is using for its monitoring connections. This defaults to 323; there
+would rarely be a need to change this.
+.RE
+.sp
+\fB\-f\fP \fIfile\fP
+.RS 4
+This option is ignored and is provided only for compatibility.
+.RE
+.sp
+\fB\-a\fP
+.RS 4
+This option is ignored and is provided only for compatibility.
+.RE
+.sp
+\fB\-v\fP
+.RS 4
+With this option \fBchronyc\fP displays its version number on the terminal and
+exits.
+.RE
+.SH "COMMANDS"
+.sp
+This section describes each of the commands available within the \fBchronyc\fP
+program.
+.SS "System clock"
+.sp
+\fBtracking\fP
+.RS 4
+The \fBtracking\fP command displays parameters about the system\(cqs clock
+performance. An example of the output is shown below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Reference ID    : CB00710F (foo.example.net)
+Stratum         : 3
+Ref time (UTC)  : Fri Jan 27 09:49:17 2017
+System time     : 0.000006523 seconds slow of NTP time
+Last offset     : \-0.000006747 seconds
+RMS offset      : 0.000035822 seconds
+Frequency       : 3.225 ppm slow
+Residual freq   : \-0.000 ppm
+Skew            : 0.129 ppm
+Root delay      : 0.013639022 seconds
+Root dispersion : 0.001100737 seconds
+Update interval : 64.2 seconds
+Leap status     : Normal
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The fields are explained as follows:
+.sp
+\fBReference ID\fP
+.RS 4
+This is the reference ID and name (or IP address) of the server to which the
+computer is currently synchronised. For IPv4 addresses, the reference ID is
+equal to the address and for IPv6 addresses it is the first 32 bits of the MD5
+sum of the address.
+.sp
+If the reference ID is \fI7F7F0101\fP and there is no name or IP address, it means
+the computer is not synchronised to any external source and that you have the
+\fIlocal\fP mode operating (via the \fBlocal\fP command in \fBchronyc\fP, or the
+\fBlocal\fP directive in the configuration file).
+.sp
+The reference ID is printed as a hexadecimal number. Note that in older
+versions it used to be printed in quad\-dotted notation and could be confused
+with an IPv4 address.
+.RE
+.sp
+\fBStratum\fP
+.RS 4
+The stratum indicates how many hops away from a computer with an attached
+reference clock we are. Such a computer is a stratum\-1 computer, so the
+computer in the example is two hops away (i.e. \fIfoo.example.net\fP is a
+stratum\-2 and is synchronised from a stratum\-1).
+.RE
+.sp
+\fBRef time\fP
+.RS 4
+This is the time (UTC) at which the last measurement from the reference
+source was processed.
+.RE
+.sp
+\fBSystem time\fP
+.RS 4
+In normal operation, \fBchronyd\fP by default never steps the system clock, because
+any jump in the time can have adverse consequences for certain application
+programs. Instead, any error in the system clock is corrected by slightly
+speeding up or slowing down the system clock until the error has been removed,
+and then returning to the system clock\(cqs normal speed. A consequence of this is
+that there will be a period when the system clock (as read by other programs)
+will be different from \fBchronyd\fP\(cqs estimate of the current true time (which it
+reports to NTP clients when it is operating in server mode). The value reported
+on this line is the difference due to this effect.
+.RE
+.sp
+\fBLast offset\fP
+.RS 4
+This is the estimated local offset on the last clock update.
+.RE
+.sp
+\fBRMS offset\fP
+.RS 4
+This is a long\-term average of the offset value.
+.RE
+.sp
+\fBFrequency\fP
+.RS 4
+The \(oqfrequency\(cq is the rate by which the system\(cqs clock would be wrong if
+\fBchronyd\fP was not correcting it. It is expressed in ppm (parts per million).
+For example, a value of 1 ppm would mean that when the system\(cqs clock thinks it
+has advanced 1 second, it has actually advanced by 1.000001 seconds relative to
+true time.
+.RE
+.sp
+\fBResidual freq\fP
+.RS 4
+This shows the \(oqresidual frequency\(cq for the currently selected reference
+source. This reflects any difference between what the measurements from the
+reference source indicate the frequency should be and the frequency currently
+being used.
+.sp
+The reason this is not always zero is that a smoothing procedure is
+applied to the frequency. Each time a measurement from the reference
+source is obtained and a new residual frequency computed, the estimated
+accuracy of this residual is compared with the estimated accuracy (see
+\(oqskew\(cq next) of the existing frequency value. A weighted average is
+computed for the new frequency, with weights depending on these accuracies.
+If the measurements from the reference source follow a consistent trend, the
+residual will be driven to zero over time.
+.RE
+.sp
+\fBSkew\fP
+.RS 4
+This is the estimated error bound on the frequency.
+.RE
+.sp
+\fBRoot delay\fP
+.RS 4
+This is the total of the network path delays to the stratum\-1 computer from
+which the computer is ultimately synchronised.
+.RE
+.sp
+\fBRoot dispersion\fP
+.RS 4
+This is the total dispersion accumulated through all the computers back to
+the stratum\-1 computer from which the computer is ultimately synchronised.
+Dispersion is due to system clock resolution, statistical measurement
+variations, etc.
+.sp
+An absolute bound on the computer\(cqs clock accuracy (assuming the stratum\-1
+computer is correct) is given by:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+clock_error <= |system_time_offset| + root_dispersion + (0.5 * root_delay)
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBUpdate interval\fP
+.RS 4
+This is the interval between the last two clock updates.
+.RE
+.sp
+\fBLeap status\fP
+.RS 4
+This is the leap status, which can be \fINormal\fP, \fIInsert second\fP, \fIDelete
+second\fP or \fINot synchronised\fP.
+.RE
+.RE
+.sp
+\fBmakestep\fP, \fBmakestep\fP \fIthreshold\fP \fIlimit\fP
+.RS 4
+Normally \fBchronyd\fP 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.
+.sp
+The \fBmakestep\fP command can be used in this situation. There are two forms of
+the command. The first form has no parameters. It tells \fBchronyd\fP to cancel any
+remaining correction that was being slewed and jump the system clock by the
+equivalent amount, making it correct immediately.
+.sp
+The second form configures the automatic stepping, similarly to the
+\fBmakestep\fP directive. It has two parameters,
+stepping threshold (in seconds) and number of future clock updates for which
+the threshold will be active. This can be used with the \fBburst\fP
+command to quickly make a new measurement and correct the clock by stepping if
+needed, without waiting for \fBchronyd\fP to complete the measurement and update
+the clock.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+makestep 0.1 1
+burst 1/2
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+BE WARNED: Certain software will be seriously affected by such jumps in the
+system time. (That is the reason why \fBchronyd\fP uses slewing normally.)
+.RE
+.sp
+\fBmaxupdateskew\fP \fIskew\-in\-ppm\fP
+.RS 4
+This command has the same effect as the
+\fBmaxupdateskew\fP directive in the
+configuration file.
+.RE
+.sp
+\fBwaitsync\fP [\fImax\-tries\fP [\fImax\-correction\fP [\fImax\-skew\fP [\fIinterval\fP]]]]
+.RS 4
+The \fBwaitsync\fP command waits for \fBchronyd\fP to synchronise.
+.sp
+Up to four optional arguments can be specified. The first is the maximum number
+of tries before giving up and returning a non\-zero error code. When 0 is
+specified, or there are no arguments, the number of tries will not be limited.
+.sp
+The second and third arguments are the maximum allowed remaining correction of
+the system clock and the maximum allowed skew (in ppm) as reported by the
+\fBtracking\fP command in the \fBSystem time\fP and \fBSkew\fP fields. If not
+specified or zero, the value will not be checked.
+.sp
+The fourth argument is the interval specified in seconds in which the check is
+repeated. The interval is 10 seconds by default.
+.sp
+An example is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+waitsync 60 0.01
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+which will wait up to about 10 minutes (60 times 10 seconds) for \fBchronyd\fP to
+synchronise to a source and the remaining correction to be less than 10
+milliseconds.
+.RE
+.SS "Time sources"
+.sp
+\fBsources\fP [\fB\-v\fP]
+.RS 4
+This command displays information about the current time sources that \fBchronyd\fP
+is accessing.
+.sp
+The optional argument \fB\-v\fP can be specified, meaning \fIverbose\fP. In this case,
+extra caption lines are shown as a reminder of the meanings of the columns.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+210 Number of sources = 3
+MS Name/IP address         Stratum Poll Reach LastRx Last sample
+===============================================================================
+#* GPS0                          0   4   377    11   \-479ns[ \-621ns] +/\-  134ns
+^? foo.example.net               2   6   377    23   \-923us[ \-924us] +/\-   43ms
+^+ bar.example.net               1   6   377    21  \-2629us[\-2619us] +/\-   86ms
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The columns are as follows:
+.sp
+\fBM\fP
+.RS 4
+This indicates the mode of the source. \fI^\fP means a server, \fI=\fP means a peer
+and \fI#\fP indicates a locally connected reference clock.
+.RE
+.sp
+\fBS\fP
+.RS 4
+This column indicates the state of the source.
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fI*\fP indicates the source to which \fBchronyd\fP is currently synchronised.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fI+\fP indicates acceptable sources which are combined with the selected
+source.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fI\-\fP indicates acceptable sources which are excluded by the combining
+algorithm.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fI?\fP indicates sources to which connectivity has been lost or whose packets
+do not pass all tests. It is also shown at start\-up, until at least 3 samples
+have been gathered from it.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fIx\fP indicates a clock which \fBchronyd\fP thinks is a falseticker (i.e. its
+time is inconsistent with a majority of other sources).
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fI~\fP indicates a source whose time appears to have too much variability.
+.RE
+.RE
+.sp
+\fBName/IP address\fP
+.RS 4
+This shows the name or the IP address of the source, or reference ID for reference
+clocks.
+.RE
+.sp
+\fBStratum\fP
+.RS 4
+This shows the stratum of the source, as reported in its most recently
+received sample. Stratum 1 indicates a computer with a locally attached
+reference clock. A computer that is synchronised to a stratum 1 computer is
+at stratum 2. A computer that is synchronised to a stratum 2 computer is at
+stratum 3, and so on.
+.RE
+.sp
+\fBPoll\fP
+.RS 4
+This shows the rate at which the source is being polled, as a base\-2
+logarithm of the interval in seconds. Thus, a value of 6 would indicate that
+a measurement is being made every 64 seconds. \fBchronyd\fP automatically varies
+the polling rate in response to prevailing conditions.
+.RE
+.sp
+\fBReach\fP
+.RS 4
+This shows the source\(cqs reachability register printed as an octal number. The
+register has 8 bits and is updated on every received or missed packet from
+the source. A value of 377 indicates that a valid reply was received for all
+from the last eight transmissions.
+.RE
+.sp
+\fBLastRx\fP
+.RS 4
+This column shows how long ago the last sample was received from the source.
+This is normally in seconds. The letters \fIm\fP, \fIh\fP, \fId\fP or \fIy\fP indicate
+minutes, hours, days, or years.
+.RE
+.sp
+\fBLast sample\fP
+.RS 4
+This column shows the offset between the local clock and the source at the
+last measurement. The number in the square brackets shows the actual measured
+offset. This can be suffixed by \fIns\fP (indicating nanoseconds), \fIus\fP
+(indicating microseconds), \fIms\fP (indicating milliseconds), or \fIs\fP (indicating
+seconds). The number to the left of the square brackets shows the original
+measurement, adjusted to allow for any slews applied to the local clock
+since. The number following the \fI+/\-\fP indicator shows the margin of error in
+the measurement. Positive offsets indicate that the local clock is ahead of
+the source.
+.RE
+.RE
+.sp
+\fBsourcestats\fP [\fB\-v\fP]
+.RS 4
+The \fBsourcestats\fP command displays information about the drift rate and offset
+estimation process for each of the sources currently being examined by
+\fBchronyd\fP.
+.sp
+The optional argument \fB\-v\fP can be specified, meaning \fIverbose\fP. In this case,
+extra caption lines are shown as a reminder of the meanings of the columns.
+.sp
+An example report is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+210 Number of sources = 1
+Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev
+===============================================================================
+foo.example.net            11   5   46m     \-0.001      0.045      1us    25us
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The columns are as follows:
+.sp
+\fBName/IP Address\fP
+.RS 4
+This is the name or IP address of the NTP server (or peer) or reference ID of the
+reference clock to which the rest of the line relates.
+.RE
+.sp
+\fBNP\fP
+.RS 4
+This is the number of sample points currently being retained for the server.
+The drift rate and current offset are estimated by performing a linear
+regression through these points.
+.RE
+.sp
+\fBNR\fP
+.RS 4
+This is the number of runs of residuals having the same sign following the
+last regression. If this number starts to become too small relative to the
+number of samples, it indicates that a straight line is no longer a good fit
+to the data. If the number of runs is too low, \fBchronyd\fP discards older
+samples and re\-runs the regression until the number of runs becomes
+acceptable.
+.RE
+.sp
+\fBSpan\fP
+.RS 4
+This is the interval between the oldest and newest samples. If no unit is
+shown the value is in seconds. In the example, the interval is 46 minutes.
+.RE
+.sp
+\fBFrequency\fP
+.RS 4
+This is the estimated residual frequency for the server, in parts per
+million. In this case, the computer\(cqs clock is estimated to be running 1 part
+in 10^9 slow relative to the server.
+.RE
+.sp
+\fBFreq Skew\fP
+.RS 4
+This is the estimated error bounds on \fBFreq\fP (again in parts per million).
+.RE
+.sp
+\fBOffset\fP
+.RS 4
+This is the estimated offset of the source.
+.RE
+.sp
+\fBStd Dev\fP
+.RS 4
+This is the estimated sample standard deviation.
+.RE
+.RE
+.sp
+\fBreselect\fP
+.RS 4
+To avoid excessive switching between sources, \fBchronyd\fP can stay synchronised
+to a source even when it is not currently the best one among the available
+sources.
+.sp
+The \fBreselect\fP command can be used to force \fBchronyd\fP to reselect the best
+synchronisation source.
+.RE
+.sp
+\fBreselectdist\fP \fIdistance\fP
+.RS 4
+The \fBreselectdist\fP command sets the reselection distance. It is equivalent to
+the \fBreselectdist\fP directive in the
+configuration file.
+.RE
+.SS "NTP sources"
+.sp
+\fBactivity\fP
+.RS 4
+This command reports the number of servers and peers that are online and
+offline. If the \fBauto_offline\fP option is used in specifying some of the servers
+or peers, the \fBactivity\fP command can be useful for detecting when all of them
+have entered the offline state after the network link has been disconnected.
+.sp
+The report shows the number of servers and peers in 5 states:
+.sp
+\fBonline\fP
+.RS 4
+the server or peer is currently online (i.e. assumed by \fBchronyd\fP to be reachable)
+.RE
+.sp
+\fBoffline\fP
+.RS 4
+the server or peer is currently offline (i.e. assumed by \fBchronyd\fP to be
+unreachable, and no measurements from it will be attempted.)
+.RE
+.sp
+\fBburst_online\fP
+.RS 4
+a burst command has been initiated for the server or peer and is being
+performed; after the burst is complete, the server or peer will be returned to
+the online state.
+.RE
+.sp
+\fBburst_offline\fP
+.RS 4
+a burst command has been initiated for the server or peer and is being
+performed; after the burst is complete, the server or peer will be returned to
+the offline state.
+.RE
+.sp
+\fBunresolved\fP
+.RS 4
+the name of the server or peer was not resolved to an address yet; this source is
+not visible in the \fBsources\fP and \fBsourcestats\fP reports.
+.RE
+.RE
+.sp
+\fBntpdata\fP [\fIaddress\fP]
+.RS 4
+The \fBntpdata\fP command displays the last valid measurement and other
+NTP\-specific information about the specified NTP source, or all NTP sources if
+no address was specified. An example of the output is shown below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Remote address  : 203.0.113.15 (CB00710F)
+Remote port     : 123
+Local address   : 203.0.113.74 (CB00714A)
+Leap status     : Normal
+Version         : 4
+Mode            : Server
+Stratum         : 1
+Poll interval   : 10 (1024 seconds)
+Precision       : \-24 (0.000000060 seconds)
+Root delay      : 0.000015 seconds
+Root dispersion : 0.000015 seconds
+Reference ID    : 47505300 (GPS)
+Reference time  : Fri Nov 25 15:22:12 2016
+Offset          : \-0.000060878 seconds
+Peer delay      : 0.000175634 seconds
+Peer dispersion : 0.000000681 seconds
+Response time   : 0.000053050 seconds
+Jitter asymmetry: +0.00
+NTP tests       : 111 111 1111
+Interleaved     : No
+Authenticated   : No
+TX timestamping : Kernel
+RX timestamping : Kernel
+Total TX        : 24
+Total RX        : 24
+Total valid RX  : 24
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The fields are explained as follows:
+.sp
+\fBRemote address\fP
+.RS 4
+The IP address of the NTP server or peer, and the corresponding reference ID.
+.RE
+.sp
+\fBRemote port\fP
+.RS 4
+The UDP port number to which the request was sent. The standard NTP port is
+123.
+.RE
+.sp
+\fBLocal address\fP
+.RS 4
+The local IP address which received the response, and the corresponding
+reference ID.
+.RE
+.sp
+\fBLeap status\fP, \fBVersion\fP, \fBMode\fP, \fBStratum\fP, \fBPoll interval\fP, \fBPrecision\fP, \fBRoot delay\fP, \fBRoot dispersion\fP, \fBReference ID\fP, \fBReference time\fP
+.RS 4
+The NTP values from the last valid response.
+.RE
+.sp
+\fBOffset\fP, \fBPeer delay\fP, \fBPeer dispersion\fP
+.RS 4
+The measured values.
+.RE
+.sp
+\fBResponse time\fP
+.RS 4
+The time the server or peer spent in processing of the request and waiting
+before sending the response.
+.RE
+.sp
+\fBJitter asymmetry\fP
+.RS 4
+The estimated asymmetry of network jitter on the path to the source. 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.
+.RE
+.sp
+\fBNTP tests\fP
+.RS 4
+Results of RFC 5905 tests 1 through 3, 5 through 7, and tests for maximum
+delay, delay ratio, delay dev ratio, and synchronisation loop.
+.RE
+.sp
+\fBInterleaved\fP
+.RS 4
+This shows if the response was in the interleaved mode.
+.RE
+.sp
+\fBAuthenticated\fP
+.RS 4
+This shows if the response was authenticated.
+.RE
+.sp
+\fBTX timestamping\fP
+.RS 4
+The source of the local transmit timestamp. Valid values are \fIDaemon\fP,
+\fIKernel\fP, and \fIHardware\fP.
+.RE
+.sp
+\fBRX timestamping\fP
+.RS 4
+The source of the local receive timestamp.
+.RE
+.sp
+\fBTotal TX\fP
+.RS 4
+The number of packets sent to the source.
+.RE
+.sp
+\fBTotal RX\fP
+.RS 4
+The number of all packets received from the source.
+.RE
+.sp
+\fBTotal valid RX\fP
+.RS 4
+The number of valid packets received from the source.
+.RE
+.RE
+.sp
+\fBadd peer\fP \fIaddress\fP [\fIoption\fP]...
+.RS 4
+The \fBadd peer\fP command allows a new NTP peer to be added whilst
+\fBchronyd\fP is running.
+.sp
+Following the words \fBadd peer\fP, the syntax of the following
+parameters and options is similar to that for the
+\fBpeer\fP directive in the configuration file.
+The following peer options can be set in the command: \fBport\fP, \fBminpoll\fP,
+\fBmaxpoll\fP, \fBpresend\fP, \fBmaxdelayratio\fP, \fBmaxdelay\fP, \fBkey\fP.
+.sp
+An example of using this command is shown below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+add peer foo.example.net minpoll 6 maxpoll 10 key 25
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBadd server\fP \fIaddress\fP [\fIoption\fP]...
+.RS 4
+The \fBadd server\fP command allows a new NTP server to be added whilst
+\fBchronyd\fP is running.
+.sp
+Following the words \fBadd server\fP, the syntax of the following parameters and
+options is similar to that for the \fBserver\fP
+directive in the configuration file.
+The following server options can be set in the command: \fBport\fP, \fBminpoll\fP,
+\fBmaxpoll\fP, \fBpresend\fP, \fBmaxdelayratio\fP, \fBmaxdelay\fP, \fBkey\fP.
+.sp
+An example of using this command is shown below:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+add server foo.example.net minpoll 6 maxpoll 10 key 25
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBdelete\fP \fIaddress\fP
+.RS 4
+The \fBdelete\fP command allows an NTP server or peer to be removed
+from the current set of sources.
+.RE
+.sp
+\fBburst\fP \fIgood\fP/\fImax\fP [\fImask\fP/\fImasked\-address\fP], \fBburst\fP \fIgood\fP/\fImax\fP [\fImasked\-address\fP/\fImasked\-bits\fP], \fBburst\fP \fIgood\fP/\fImax\fP [\fIaddress\fP]
+.RS 4
+The \fBburst\fP command tells \fBchronyd\fP to make a set of measurements to each of
+its NTP sources over a short duration (rather than the usual periodic
+measurements that it makes). After such a burst, \fBchronyd\fP will revert to the
+previous state for each source. This might be either online, if the source was
+being periodically measured in the normal way, or offline, if the source had
+been indicated as being offline. (A source can be switched between the online
+and offline states with the \fBonline\fP and \fBoffline\fP
+commands.)
+.sp
+The \fImask\fP and \fImasked\-address\fP arguments are optional, in which case \fBchronyd\fP
+will initiate a burst for all of its currently defined sources.
+.sp
+The arguments have the following meaning and format:
+.sp
+\fIgood\fP
+.RS 4
+This defines the number of good measurements that \fBchronyd\fP will want to
+obtain from each source. A measurement is good if it passes certain tests,
+for example, the round trip time to the source must be acceptable. (This
+allows \fBchronyd\fP to reject measurements that are likely to be bogus.)
+.RE
+.sp
+\fImax\fP
+.RS 4
+This defines the maximum number of measurements that \fBchronyd\fP will attempt
+to make, even if the required number of good measurements has not been
+obtained.
+.RE
+.sp
+\fImask\fP
+.RS 4
+This is an IP address with which the IP address of each of \fBchronyd\fP\(cqs
+sources is to be masked.
+.RE
+.sp
+\fImasked\-address\fP
+.RS 4
+This is an IP address. If the masked IP address of a source matches this
+value then the burst command is applied to that source.
+.RE
+.sp
+\fImasked\-bits\fP
+.RS 4
+This can be used with \fImasked\-address\fP for CIDR notation, which is a shorter
+alternative to the form with mask.
+.RE
+.sp
+\fIaddress\fP
+.RS 4
+This is an IP address or a hostname. The burst command is applied only to
+that source.
+.RE
+.RE
+.sp
+
+.RS 4
+.sp
+If no \fImask\fP or \fImasked\-address\fP arguments are provided, every source will be
+matched.
+.sp
+An example of the two\-argument form of the command is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+burst 2/10
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This will cause \fBchronyd\fP to attempt to get two good measurements from each
+source, stopping after two have been obtained, but in no event will it try more
+than ten probes to the source.
+.sp
+Examples of the four\-argument form of the command are:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+burst 2/10 255.255.0.0/1.2.0.0
+burst 2/10 2001:db8:789a::/48
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+In the first case, the two out of ten sampling will only be applied to sources
+whose IPv4 addresses are of the form \fI1.2.x.y\fP, where \fIx\fP and \fIy\fP are
+arbitrary. In the second case, the sampling will be applied to sources whose
+IPv6 addresses have first 48 bits equal to \fI2001:db8:789a\fP.
+.sp
+Example of the three\-argument form of the command is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+burst 2/10 foo.example.net
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBmaxdelay\fP \fIaddress\fP \fIdelay\fP
+.RS 4
+This allows the \fBmaxdelay\fP option for one of the sources to be modified, in the
+same way as specifying the \fBmaxdelay\fP option for the
+\fBserver\fP directive in the configuration file.
+.RE
+.sp
+\fBmaxdelaydevratio\fP \fIaddress\fP \fIratio\fP
+.RS 4
+This allows the \fBmaxdelaydevratio\fP option for one of the sources to be
+modified, in the same way as specifying the \fBmaxdelaydevratio\fP option for the
+\fBserver\fP directive in the configuration file.
+.RE
+.sp
+\fBmaxdelayratio\fP \fIaddress\fP \fIratio\fP
+.RS 4
+This allows the \fBmaxdelayratio\fP option for one of the sources to be modified,
+in the same way as specifying the \fBmaxdelayratio\fP option for the
+\fBserver\fP directive in the configuration file.
+.RE
+.sp
+\fBmaxpoll\fP \fIaddress\fP \fImaxpoll\fP
+.RS 4
+The \fBmaxpoll\fP command is used to modify the maximum polling interval for one of
+the current set of sources. It is equivalent to the \fBmaxpoll\fP option in the
+\fBserver\fP directive in the configuration file.
+.sp
+Note that the new maximum polling interval only takes effect after the next
+measurement has been made.
+.RE
+.sp
+\fBminpoll\fP \fIaddress\fP \fIminpoll\fP
+.RS 4
+The \fBminpoll\fP command is used to modify the minimum polling interval for one of
+the current set of sources. It is equivalent to the \fBminpoll\fP option in the
+\fBserver\fP directive in the configuration file.
+.sp
+Note that the new minimum polling interval only takes effect after the next
+measurement has been made.
+.RE
+.sp
+\fBminstratum\fP \fIaddress\fP \fIminstratum\fP
+.RS 4
+The \fBminstratum\fP command is used to modify the minimum stratum for one of the
+current set of sources. It is equivalent to the \fBminstratum\fP option in the
+\fBserver\fP directive in the configuration file.
+.RE
+.sp
+\fBoffline\fP [\fIaddress\fP], \fBoffline\fP [\fImasked\-address\fP/\fImasked\-bits\fP], \fBoffline\fP [\fImask\fP/\fImasked\-address\fP]
+.RS 4
+The \fBoffline\fP command is used to warn \fBchronyd\fP that the network connection to
+a particular host or hosts is about to be lost, e.g. on computers with
+intermittent connection to their time sources.
+.sp
+Another case where \fBoffline\fP could be used is where a computer serves time to a
+local group of computers, and has a permanent connection to true time servers
+outside the organisation. However, the external connection is heavily loaded at
+certain times of the day and the measurements obtained are less reliable at
+those times. In this case, it is probably most useful to determine the
+gain or loss rate during the quiet periods and let the whole network coast through
+the loaded periods. The \fBoffline\fP and \fBonline\fP commands can be used to achieve
+this.
+.sp
+There are four forms of the \fBoffline\fP command. The first form is a wildcard,
+meaning all sources. The second form allows an IP address mask and a masked
+address to be specified. The third form uses CIDR notation. The fourth form
+uses an IP address or a hostname. These forms are illustrated below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+offline
+offline 255.255.255.0/1.2.3.0
+offline 2001:db8:789a::/48
+offline foo.example.net
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The second form means that the \fBoffline\fP command is to be applied to any source
+whose IPv4 address is in the \fI1.2.3\fP subnet. (The host\(cqs address is logically
+and\-ed with the mask, and if the result matches the \fImasked\-address\fP the host
+is processed.) The third form means that the command is to be applied to all
+sources whose IPv6 addresses have their first 48 bits equal to \fI2001:db8:789a\fP. The
+fourth form means that the command is to be applied only to that one source.
+.sp
+The wildcard form of the address is equivalent to:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+offline 0.0.0.0/0.0.0.0
+offline ::/0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBonline\fP [\fIaddress\fP], \fBonline\fP [\fImasked\-address\fP/\fImasked\-bits\fP], \fBonline\fP [\fImask\fP/\fImasked\-address\fP]
+.RS 4
+The \fBonline\fP command is opposite in function to the \fBoffline\fP
+command. It is used to advise \fBchronyd\fP that network connectivity to a
+particular source or sources has been restored.
+.sp
+The syntax is identical to that of the \fBoffline\fP command.
+.RE
+.sp
+\fBpolltarget\fP \fIaddress\fP \fIpolltarget\fP
+.RS 4
+The \fBpolltarget\fP command is used to modify the poll target for one of the
+current set of sources. It is equivalent to the \fBpolltarget\fP option in the
+\fBserver\fP directive in the configuration file.
+.RE
+.sp
+\fBrefresh\fP
+.RS 4
+The \fBrefresh\fP command can be used to force \fBchronyd\fP to resolve the names of
+configured sources to IP addresses again, e.g. after suspending and resuming
+the machine in a different network.
+.sp
+Sources that stop responding will be replaced with newly resolved addresses
+automatically after 8 polling intervals, but this command can still be useful
+to replace them immediately and not wait until they are marked as unreachable.
+.RE
+.SS "Manual time input"
+.sp
+\fBmanual\fP \fBon\fP, \fBmanual\fP \fBoff\fP, \fBmanual\fP \fBdelete\fP \fIindex\fP, \fBmanual\fP \fBlist\fP, \fBmanual\fP \fBreset\fP
+.RS 4
+The manual command enables and disables use of the \fBsettime\fP
+command, and is used to modify the behaviour of the manual clock driver.
+.sp
+The \fBon\fP form of the command enables use of the \fBsettime\fP command.
+.sp
+The \fBoff\fP form of the command disables use of the \fBsettime\fP command.
+.sp
+The \fBlist\fP form of the command lists all the samples currently stored in
+\fBchronyd\fP. The output is illustrated below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+210 n_samples = 1
+#    Date  Time(UTC)    Slewed   Original   Residual
+====================================================
+ 0 27Jan99 22:09:20       0.00       0.97       0.00
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The columns are as as follows:
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+The sample index (used for the \fBmanual delete\fP command).
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+The date and time of the sample.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+The system clock error when the timestamp was entered, adjusted to allow
+for changes made to the system clock since.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 4." 4.2
+.\}
+The system clock error when the timestamp was entered, as it originally was
+(without allowing for changes to the system clock since).
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 5.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 5." 4.2
+.\}
+The regression residual at this point, in seconds. This allows \(oqoutliers\(cq
+to be easily spotted, so that they can be deleted using the \fBmanual delete\fP
+command.
+.RE
+.RE
+.sp
+
+.RS 4
+.sp
+The \fBdelete\fP form of the command deletes a single sample. The parameter is the
+index of the sample, as shown in the first column of the output from \fBmanual
+list\fP. Following deletion of the data point, the current error and drift rate
+are re\-estimated from the remaining data points and the system clock trimmed if
+necessary. This option is intended to allow \(oqoutliers\(cq to be discarded, i.e.
+samples where the administrator realises they have entered a very poor
+timestamp.
+.sp
+The \fBreset\fP form of the command deletes all samples at once. The system clock
+is left running as it was before the command was entered.
+.RE
+.sp
+\fBsettime\fP \fItime\fP
+.RS 4
+The \fBsettime\fP command allows the current time to be entered manually, if this
+option has been configured into \fBchronyd\fP. (It can be configured either with
+the \fBmanual\fP directive in the configuration file,
+or with the \fBmanual\fP command of \fBchronyc\fP.)
+.sp
+It should be noted that the computer\(cqs sense of time will only be as accurate
+as the reference you use for providing this input (e.g. your watch), as well as
+how well you can time the press of the return key.
+.sp
+Providing your computer\(cqs time zone is set up properly, you will be able to
+enter a local time (rather than UTC).
+.sp
+The response to a successful \fBsettime\fP command indicates the amount that the
+computer\(cqs clock was wrong. It should be apparent from this if you have entered
+the time wrongly, e.g. with the wrong time zone.
+.sp
+The rate of drift of the system clock is estimated by a regression process
+using the entered measurement and all previous measurements entered during the
+present run of \fBchronyd\fP. However, the entered measurement is used for
+adjusting the current clock offset (rather than the estimated intercept from
+the regression, which is ignored). Contrast what happens with the
+\fBmanual delete\fP command, where the intercept is used to set the
+current offset (since there is no measurement that has just been entered in
+that case).
+.sp
+The time is parsed by the public domain \fIgetdate\fP algorithm. Consequently, you
+can only specify time to the nearest second.
+.sp
+Examples of inputs that are valid are shown below:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+settime 16:30
+settime 16:30:05
+settime Nov 21, 2015 16:30:05
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+For a full description of getdate, see the getdate documentation
+(bundled, for example, with the source for GNU tar).
+.RE
+.SS "NTP access"
+.sp
+\fBaccheck\fP \fIaddress\fP
+.RS 4
+This command allows you to check whether client NTP access is allowed from a
+particular host.
+.sp
+Examples of use, showing a named host and a numeric IP address, are as follows:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+accheck foo.example.net
+accheck 1.2.3.4
+accheck 2001:db8::1
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This command can be used to examine the effect of a series of \fBallow\fP, \fBallow
+all\fP, \fBdeny\fP, and \fBdeny all\fP commands specified either via \fBchronyc\fP, or in
+\fBchronyd\fP\(cqs configuration file.
+.RE
+.sp
+\fBclients\fP
+.RS 4
+This command shows a list of clients that have accessed the server, through
+either the NTP or command ports. It does not include accesses over
+the Unix domain command socket. There are no arguments.
+.sp
+An example of the output is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Hostname                      NTP   Drop Int IntL Last     Cmd   Drop Int  Last
+===============================================================================
+localhost                       2      0   2   \-   133      15      0  \-1     7
+foo.example.net                12      0   6   \-    23       0      0   \-     \-
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Each row shows the data for a single host. Only hosts that have passed the host
+access checks (set with the \fBallow\fP, \fBdeny\fP,
+\fBcmdallow\fP and \fBcmddeny\fP commands or configuration
+file directives) are logged. The intervals are displayed as a power of 2 in
+seconds.
+.sp
+The columns are as follows:
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+The hostname of the client.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+The number of NTP packets received from the client.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+The number of NTP packets dropped to limit the response rate.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 4." 4.2
+.\}
+The average interval between NTP packets.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 5.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 5." 4.2
+.\}
+The average interval between NTP packets after limiting the response rate.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 6.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 6." 4.2
+.\}
+Time since the last NTP packet was received
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 7.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 7." 4.2
+.\}
+The number of command packets received from the client.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 8.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 8." 4.2
+.\}
+The number of command packets dropped to limit the response rate.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 9.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 9." 4.2
+.\}
+The average interval between command packets.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 10.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 10." 4.2
+.\}
+Time since the last command packet was received.
+.RE
+.RE
+.sp
+\fBserverstats\fP
+.RS 4
+The \fBserverstats\fP command displays how many valid NTP and command requests
+\fBchronyd\fP as a server received from clients, how many of them were dropped to
+limit the response rate as configured by the
+\fBratelimit\fP and
+\fBcmdratelimit\fP directives, and how many
+client log records were dropped due to the memory limit configured by the
+\fBclientloglimit\fP directive. An example of
+the output is shown below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+NTP packets received       : 1598
+NTP packets dropped        : 8
+Command packets received   : 19
+Command packets dropped    : 0
+Client log records dropped : 0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBallow\fP [\fBall\fP] [\fIsubnet\fP]
+.RS 4
+The effect of the allow command is identical to the
+\fBallow\fP directive in the configuration file.
+.sp
+The syntax is illustrated in the following examples:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+allow foo.example.net
+allow all 1.2
+allow 3.4.5
+allow 6.7.8/22
+allow 6.7.8.9/22
+allow 2001:db8:789a::/48
+allow 0/0
+allow ::/0
+allow
+allow all
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBdeny\fP [\fBall\fP] [\fIsubnet\fP]
+.RS 4
+The effect of the allow command is identical to the
+\fBdeny\fP directive in the configuration file.
+.sp
+The syntax is illustrated in the following examples:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+deny foo.example.net
+deny all 1.2
+deny 3.4.5
+deny 6.7.8/22
+deny 6.7.8.9/22
+deny 2001:db8:789a::/48
+deny 0/0
+deny ::/0
+deny
+deny all
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBlocal\fP [\fIoption\fP]..., \fBlocal\fP \fBoff\fP
+.RS 4
+The \fBlocal\fP command allows \fBchronyd\fP to be told that it is to appear as a
+reference source, even if it is not itself properly synchronised to an external
+source. (This can be used on isolated networks, to allow one computer to be a
+master time server with the other computers slaving to it.)
+.sp
+The first form enables the local reference mode on the host. The syntax is
+identical to the \fBlocal\fP directive in the
+configuration file.
+.sp
+The second form disables the local reference mode.
+.RE
+.sp
+\fBsmoothing\fP
+.RS 4
+The \fBsmoothing\fP command displays the current state of the NTP server time
+smoothing, which can be enabled with the
+\fBsmoothtime\fP directive. An example of the
+output is shown below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Active         : Yes
+Offset         : +1.000268817 seconds
+Frequency      : \-0.142859 ppm
+Wander         : \-0.010000 ppm per second
+Last update    : 17.8 seconds ago
+Remaining time : 19988.4 seconds
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The fields are explained as follows:
+.sp
+\fBActive\fP
+.RS 4
+This shows if the server time smoothing is currently active. Possible values
+are \fIYes\fP and \fINo\fP. If the \fBleaponly\fP option is included in the \fBsmoothtime\fP
+directive, \fI(leap second only)\fP will be shown on the line.
+.RE
+.sp
+\fBOffset\fP
+.RS 4
+This is the current offset applied to the time sent to NTP clients. Positive
+value means the clients are getting time that\(cqs ahead of true time.
+.RE
+.sp
+\fBFrequency\fP
+.RS 4
+The current frequency offset of the served time. Negative value means the
+time observed by clients is running slower than true time.
+.RE
+.sp
+\fBWander\fP
+.RS 4
+The current frequency wander of the served time. Negative value means the
+time observed by clients is slowing down.
+.RE
+.sp
+\fBLast update\fP
+.RS 4
+This field shows how long ago the time smoothing process was updated, e.g.
+\fBchronyd\fP accumulated a new measurement.
+.RE
+.sp
+\fBRemaining time\fP
+.RS 4
+The time it would take for the smoothing process to get to zero offset and
+frequency if there were no more updates.
+.RE
+.RE
+.sp
+\fBsmoothtime\fP \fBactivate\fP, \fBsmoothtime\fP \fBreset\fP
+.RS 4
+The \fBsmoothtime\fP command can be used to activate or reset the server time
+smoothing process if it is configured with the
+\fBsmoothtime\fP directive.
+.RE
+.SS "Monitoring access"
+.sp
+\fBcmdaccheck\fP \fIaddress\fP
+.RS 4
+This command is similar to the \fBaccheck\fP command, except that it is
+used to check whether monitoring access is permitted from a named host.
+.sp
+Examples of use are as follows:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+cmdaccheck foo.example.net
+cmdaccheck 1.2.3.4
+cmdaccheck 2001:db8::1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBcmdallow\fP [\fBall\fP] [\fIsubnet\fP]
+.RS 4
+This is similar to the \fBallow\fP command, except that it is used to
+allow particular hosts or subnets to use \fBchronyc\fP to monitor with \fBchronyd\fP on
+the current host.
+.RE
+.sp
+\fBcmddeny\fP [\fBall\fP] [\fIsubnet\fP]
+.RS 4
+This is similar to the \fBdeny\fP command, except that it is used to allow
+particular hosts or subnets to use \fBchronyc\fP to monitor \fBchronyd\fP on the
+current host.
+.RE
+.SS "Real\-time clock (RTC)"
+.sp
+\fBrtcdata\fP
+.RS 4
+The \fBrtcdata\fP command displays the current RTC parameters.
+.sp
+An example output is shown below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+RTC ref time (GMT) : Sat May 30 07:25:56 2015
+Number of samples  : 10
+Number of runs     : 5
+Sample span period :  549
+RTC is fast by     :    \-1.632736 seconds
+RTC gains time at  :  \-107.623 ppm
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The fields have the following meaning:
+.sp
+\fBRTC ref time (GMT)\fP
+.RS 4
+This is the RTC reading the last time its error was measured.
+.RE
+.sp
+\fBNumber of samples\fP
+.RS 4
+This is the number of previous measurements being used to determine the RTC
+gain or loss rate.
+.RE
+.sp
+\fBNumber of runs\fP
+.RS 4
+This is the number of runs of residuals of the same sign following the
+regression fit for (RTC error) versus (RTC time). A value which is small
+indicates that the measurements are not well approximated by a linear model,
+and that the algorithm will tend to delete the older measurements to improve
+the fit.
+.RE
+.sp
+\fBSample span period\fP
+.RS 4
+This is the period that the measurements span (from the oldest to the
+newest). Without a unit the value is in seconds; suffixes \fIm\fP for minutes,
+\fIh\fP for hours, \fId\fP for days or \fIy\fP for years can be used.
+.RE
+.sp
+\fBRTC is fast by\fP
+.RS 4
+This is the estimate of how many seconds fast the RTC when it thought
+the time was at the reference time (above). If this value is large, you
+might (or might not) want to use the \fBtrimrtc\fP command to bring the
+RTC into line with the system clock. (Note, a large error will not affect
+\fBchronyd\fP\(cqs operation, unless it becomes so big as to start causing rounding
+errors.)
+.RE
+.sp
+\fBRTC gains time at\fP
+.RS 4
+This is the amount of time gained (positive) or lost (negative) by the real
+time clock for each second that it ticks. It is measured in parts per
+million. So if the value shown was +1, suppose the RTC was exactly right when
+it crosses a particular second boundary. Then it would be 1 microsecond fast
+when it crosses its next second boundary.
+.RE
+.RE
+.sp
+\fBtrimrtc\fP
+.RS 4
+The \fBtrimrtc\fP command is used to correct the system\(cqs real\-time clock (RTC) to
+the main system clock. It has no effect if the error between the two clocks is
+currently estimated at less than a second.
+.sp
+The command takes no arguments. It performs the following steps (if the RTC is
+more than 1 second away from the system clock):
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 1." 4.2
+.\}
+Remember the currently estimated gain or loss rate of the RTC and flush the
+previous measurements.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 2." 4.2
+.\}
+Step the real\-time clock to bring it within a second of the system clock.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 3." 4.2
+.\}
+Make several measurements to accurately determine the new offset between
+the RTC and the system clock (i.e. the remaining fraction of a second
+error).
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 4." 4.2
+.\}
+Save the RTC parameters to the RTC file (specified with the
+\fBrtcfile\fP directive in the configuration file).
+.RE
+.RE
+.sp
+
+.RS 4
+.sp
+The last step is done as a precaution against the computer suffering a power
+failure before either the daemon exits or the \fBwritertc\fP command
+is issued.
+.sp
+\fBchronyd\fP will still work perfectly well both whilst operating and across
+machine reboots even if the \fBtrimrtc\fP command is never used (and the RTC is
+allowed to drift away from true time). The \fBtrimrtc\fP command is provided as a
+method by which it can be corrected, in a manner compatible with \fBchronyd\fP
+using it to maintain accurate time across machine reboots.
+.sp
+The \fBtrimrtc\fP command can be executed automatically by \fBchronyd\fP with the
+\fBrtcautotrim\fP directive in the configuration
+file.
+.RE
+.sp
+\fBwritertc\fP
+.RS 4
+The \fBwritertc\fP command writes the currently estimated error and gain or loss rate
+parameters for the RTC to the RTC file (specified with the
+\fBrtcfile\fP directive). This information is also
+written automatically when \fBchronyd\fP is killed (by the SIGHUP, SIGINT, SIGQUIT
+or SIGTERM signals) or when the \fBtrimrtc\fP command is issued.
+.RE
+.SS "Other daemon commands"
+.sp
+\fBcyclelogs\fP
+.RS 4
+The \fBcyclelogs\fP command causes all of \fBchronyd\fP\(cqs open log files to be closed
+and re\-opened. This allows them to be renamed so that they can be periodically
+purged. An example of how to do this is shown below.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# mv /var/log/chrony/measurements.log /var/log/chrony/measurements1.log
+# chronyc cyclelogs
+# ls \-l /var/log/chrony
+\-rw\-r\-\-r\-\-   1 root     root            0 Jun  8 18:17 measurements.log
+\-rw\-r\-\-r\-\-   1 root     root        12345 Jun  8 18:17 measurements1.log
+# rm \-f measurements1.log
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+\fBdump\fP
+.RS 4
+The \fBdump\fP command causes \fBchronyd\fP to write its current history of
+measurements for each of its sources to dump files in the directory specified
+in the configuration file by the \fBdumpdir\fP
+directive. Note that \fBchronyd\fP does this automatically when it exits. This
+command is mainly useful for inspection of the history whilst \fBchronyd\fP is
+running.
+.RE
+.sp
+\fBrekey\fP
+.RS 4
+The \fBrekey\fP command causes \fBchronyd\fP to re\-read the key file specified in the
+configuration file by the \fBkeyfile\fP directive.
+.RE
+.sp
+\fBshutdown\fP
+.RS 4
+The \fBshutdown\fP command causes \fBchronyd\fP to exit. This is equivalent to sending
+the process the SIGTERM signal.
+.RE
+.SS "Client commands"
+.sp
+\fBdns\fP \fIoption\fP
+.RS 4
+The \fBdns\fP command configures how hostnames and IP addresses are resolved in
+\fBchronyc\fP. IP addresses can be resolved to hostnames when printing results of
+\fBsources\fP, \fBsourcestats\fP, \fBtracking\fP
+and \fBclients\fP commands. Hostnames are resolved in commands that
+take an address as argument.
+.sp
+There are five options:
+.sp
+\fBdns \-n\fP
+.RS 4
+Disables resolving IP addresses to hostnames. Raw IP addresses will be
+displayed.
+.RE
+.sp
+\fBdns +n\fP
+.RS 4
+Enables resolving IP addresses to hostnames. This is the default unless
+\fBchronyc\fP was started with \fB\-n\fP option.
+.RE
+.sp
+\fBdns \-4\fP
+.RS 4
+Resolves hostnames only to IPv4 addresses.
+.RE
+.sp
+\fBdns \-6\fP
+.RS 4
+Resolves hostnames only to IPv6 addresses.
+.RE
+.sp
+\fBdns \-46\fP
+.RS 4
+Resolves hostnames to both address families. This is the default behaviour
+unless \fBchronyc\fP was started with the \fB\-4\fP or \fB\-6\fP option.
+.RE
+.RE
+.sp
+\fBtimeout\fP \fItimeout\fP
+.RS 4
+The \fBtimeout\fP command sets the initial timeout for \fBchronyc\fP requests in
+milliseconds. If no response is received from \fBchronyd\fP, the timeout is doubled
+and the request is resent. The maximum number of retries is configured with the
+\fBretries\fP command.
+.sp
+By default, the timeout is 1000 milliseconds.
+.RE
+.sp
+\fBretries\fP \fIretries\fP
+.RS 4
+The \fBretries\fP command sets the maximum number of retries for \fBchronyc\fP requests
+before giving up. The response timeout is controlled by the
+\fBtimeout\fP command.
+.sp
+The default is 2.
+.RE
+.sp
+\fBkeygen\fP [\fIid\fP [\fItype\fP [\fIbits\fP]]]
+.RS 4
+The \fBkeygen\fP command generates a key that can be added to the
+key file (specified with the \fBkeyfile\fP directive)
+to allow NTP authentication between server and client, or peers. The key is
+generated from the \fI/dev/urandom\fP device and it is printed to standard output.
+.sp
+The command has three optional arguments. The first argument is the key number
+(by default 1), which will be specified with the \fBkey\fP option of the \fBserver\fP
+or \fBpeer\fP directives in the configuration file. The second argument is the hash
+function (by default SHA1 or MD5 if SHA1 is not available) and the third
+argument is the number of bits the key should have, between 80 and 4096 bits
+(by default 160 bits).
+.sp
+An example is:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+keygen 73 SHA1 256
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+which generates a 256\-bit SHA1 key with number 73. The printed line should
+then be securely transferred and added to the key files on both server and
+client, or peers.
+.RE
+.sp
+\fBexit\fP, \fBquit\fP
+.RS 4
+The \fBexit\fP and \fBquit\fP commands exit from \fBchronyc\fP and return the user to the shell.
+.RE
+.sp
+\fBhelp\fP
+.RS 4
+The \fBhelp\fP command displays a summary of the commands and their arguments.
+.RE
+.SH "SEE ALSO"
+.sp
+\fBchrony.conf(5)\fP, \fBchronyd(8)\fP
+.SH "BUGS"
+.sp
+For instructions on how to report bugs, please visit
+.URL "https://chrony.tuxfamily.org/" "" "."
+.SH "AUTHORS"
+.sp
+chrony was written by Richard Curnow, Miroslav Lichvar, and others.
\ No newline at end of file
diff --git a/chrony_3_3/doc/chronyd.adoc b/chrony_3_3/doc/chronyd.adoc
new file mode 100644
index 0000000..fc79078
--- /dev/null
+++ b/chrony_3_3/doc/chronyd.adoc
@@ -0,0 +1,186 @@
+// This file is part of chrony
+//
+// 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.
+
+= chronyd(8)
+:doctype: manpage
+:man manual: System Administration
+:man source: chrony @CHRONY_VERSION@
+
+== NAME
+
+chronyd - chrony daemon
+
+== SYNOPSIS
+
+*chronyd* [_OPTION_]... [_DIRECTIVE_]...
+
+== DESCRIPTION
+
+*chronyd* is a daemon for synchronisation of the system clock. It can
+synchronise the clock with NTP servers, reference clocks (e.g. a GPS receiver),
+and manual input using wristwatch and keyboard via *chronyc*. It can also
+operate as an NTPv4 (RFC 5905) server and peer to provide a time service to
+other computers in the network.
+
+If no configuration directives are specified on the command line, *chronyd*
+will read them from a configuration file. The compiled-in default location of
+the file is _@SYSCONFDIR@/chrony.conf_.
+
+Information messages and warnings will be logged to syslog.
+
+== OPTIONS
+
+*-4*::
+With this option hostnames will be resolved only to IPv4 addresses and only
+IPv4 sockets will be created.
+
+*-6*::
+With this option hostnames will be resolved only to IPv6 addresses and only
+IPv6 sockets will be created.
+
+*-f* _file_::
+This option can be used to specify an alternate location for the configuration
+file (default _@SYSCONFDIR@/chrony.conf_).
+
+*-n*::
+When run in this mode, the program will not detach itself from the terminal.
+
+*-d*::
+When run in this mode, the program will not detach itself from the terminal,
+and all messages will be written to the terminal instead of syslog. When
+*chronyd* was compiled with debugging support, this option can be used twice to
+print also debugging messages.
+
+*-l* _file_::
+This option specifies a file which should be used for logging instead of syslog
+or terminal.
+
+*-q*::
+When run in this mode, *chronyd* will set the system clock once and exit. It
+will not detach from the terminal.
+
+*-Q*::
+This option is similar to the *-q* option, except it only prints the offset
+without making any corrections of the clock and it allows *chronyd* to be
+started without root privileges.
+
+*-r*::
+This option will try to reload and then delete files containing sample
+histories for each of the servers and reference clocks being used. These
+histories are created by using the <<chronyc.adoc#dump,*dump*>> command in
+*chronyc*, or by setting the <<chrony.conf.adoc#dumponexit,*dumponexit*>>
+directive in the configuration file. This option is useful if you want to stop
+and restart *chronyd* briefly for any reason, e.g. to install a new version.
+However, it should be used only on systems where the kernel can maintain clock
+compensation whilst not under *chronyd*'s control (i.e. Linux, FreeBSD, NetBSD,
+Solaris, and macOS 10.13 or later).
+
+*-R*::
+When this option is used, the <<chrony.conf.adoc#initstepslew,*initstepslew*>>
+directive and the <<chrony.conf.adoc#makestep,*makestep*>> directive used with
+a positive limit will be ignored. This option is useful when restarting
+*chronyd* and can be used in conjunction with the *-r* option.
+
+*-s*::
+This option will set the system clock from the computer's real-time clock (RTC)
+or to the last modification time of the file specified by the
+<<chrony.conf.adoc#driftfile,*driftfile*>> directive. Real-time clocks are
+supported only on Linux.
++
+If used in conjunction with the *-r* flag, *chronyd* will attempt to preserve
+the old samples after setting the system clock from the RTC. This can be used
+to allow *chronyd* to perform long term averaging of the gain or loss rate
+across system reboots, and is useful for systems with intermittent access to
+network that are shut down when not in use. For this to work well, it relies
+on *chronyd* having been able to determine accurate statistics for the
+difference between the RTC and system clock last time the computer was on.
++
+If the last modification time of the drift file is later than both the current
+time and the RTC time, the system time will be set to it to restore the time
+when *chronyd* was previously stopped. This is useful on computers that have no
+RTC or the RTC is broken (e.g. it has no battery).
+
+*-t* _timeout_::
+This option sets a timeout (in seconds) after which *chronyd* will exit. If the
+clock is not synchronised, it will exit with a non-zero status. This is useful
+with the *-q* or *-Q* option to shorten the maximum time waiting for
+measurements, or with the *-r* option to limit the time when *chronyd* is
+running, but still allow it to adjust the frequency of the system clock.
+
+*-u* _user_::
+This option sets the name of the system user to which *chronyd* will switch
+after start in order to drop root privileges. It overrides the
+<<chrony.conf.adoc#user,*user*>> directive (default _@DEFAULT_USER@_).
++
+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.
+
+*-F* _level_::
+This option configures a system call filter when *chronyd* is compiled with
+support for the Linux secure computing (seccomp) facility. In level 1 the
+process is killed when a forbidden system call is made, in level -1 the SIGSYS
+signal is thrown instead and in level 0 the filter is disabled (default 0).
++
+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.
+
+*-P* _priority_::
+On Linux, this option 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.
+
+*-m*::
+This option will lock *chronyd* into RAM so that it will never be paged out.
+This mode is only supported on Linux.
+
+*-x*::
+This option disables the control of the system clock. *chronyd* will not try to
+make any adjustments of the clock. It will assume the clock is free running and
+still track its offset and frequency relative to the estimated true time. This
+option allows *chronyd* to run without the capability to adjust or set the
+system clock (e.g. in some containers) in order to operate as an NTP server. It
+is not recommended to run *chronyd* (with or without *-x*) when another process
+is controlling the system clock.
+
+*-v*::
+With this option *chronyd* will print version number to the terminal and exit.
+
+== FILES
+
+_@SYSCONFDIR@/chrony.conf_
+
+== SEE ALSO
+
+<<chronyc.adoc#,*chronyc(1)*>>, <<chrony.conf.adoc#,*chrony.conf(5)*>>
+
+== 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/chrony_3_3/doc/chronyd.man.in b/chrony_3_3/doc/chronyd.man.in
new file mode 100644
index 0000000..ab3acf8
--- /dev/null
+++ b/chrony_3_3/doc/chronyd.man.in
@@ -0,0 +1,211 @@
+'\" t
+.\"     Title: chronyd
+.\"    Author: [see the "AUTHORS" section]
+.\" Generator: Asciidoctor 1.5.6.1
+.\"      Date: 2018-04-04
+.\"    Manual: System Administration
+.\"    Source: chrony @CHRONY_VERSION@
+.\"  Language: English
+.\"
+.TH "CHRONYD" "8" "2018-04-04" "chrony @CHRONY_VERSION@" "System Administration"
+.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"
+chronyd \- chrony daemon
+.SH "SYNOPSIS"
+.sp
+\fBchronyd\fP [\fIOPTION\fP]... [\fIDIRECTIVE\fP]...
+.SH "DESCRIPTION"
+.sp
+\fBchronyd\fP is a daemon for synchronisation of the system clock. It can
+synchronise the clock with NTP servers, reference clocks (e.g. a GPS receiver),
+and manual input using wristwatch and keyboard via \fBchronyc\fP. It can also
+operate as an NTPv4 (RFC 5905) server and peer to provide a time service to
+other computers in the network.
+.sp
+If no configuration directives are specified on the command line, \fBchronyd\fP
+will read them from a configuration file. The compiled\-in default location of
+the file is \fI@SYSCONFDIR@/chrony.conf\fP.
+.sp
+Information messages and warnings will be logged to syslog.
+.SH "OPTIONS"
+.sp
+\fB\-4\fP
+.RS 4
+With this option hostnames will be resolved only to IPv4 addresses and only
+IPv4 sockets will be created.
+.RE
+.sp
+\fB\-6\fP
+.RS 4
+With this option hostnames will be resolved only to IPv6 addresses and only
+IPv6 sockets will be created.
+.RE
+.sp
+\fB\-f\fP \fIfile\fP
+.RS 4
+This option can be used to specify an alternate location for the configuration
+file (default \fI@SYSCONFDIR@/chrony.conf\fP).
+.RE
+.sp
+\fB\-n\fP
+.RS 4
+When run in this mode, the program will not detach itself from the terminal.
+.RE
+.sp
+\fB\-d\fP
+.RS 4
+When run in this mode, the program will not detach itself from the terminal,
+and all messages will be written to the terminal instead of syslog. When
+\fBchronyd\fP was compiled with debugging support, this option can be used twice to
+print also debugging messages.
+.RE
+.sp
+\fB\-l\fP \fIfile\fP
+.RS 4
+This option specifies a file which should be used for logging instead of syslog
+or terminal.
+.RE
+.sp
+\fB\-q\fP
+.RS 4
+When run in this mode, \fBchronyd\fP will set the system clock once and exit. It
+will not detach from the terminal.
+.RE
+.sp
+\fB\-Q\fP
+.RS 4
+This option is similar to the \fB\-q\fP option, except it only prints the offset
+without making any corrections of the clock and it allows \fBchronyd\fP to be
+started without root privileges.
+.RE
+.sp
+\fB\-r\fP
+.RS 4
+This option will try to reload and then delete files containing sample
+histories for each of the servers and reference clocks being used. These
+histories are created by using the \fBdump\fP command in
+\fBchronyc\fP, or by setting the \fBdumponexit\fP
+directive in the configuration file. This option is useful if you want to stop
+and restart \fBchronyd\fP briefly for any reason, e.g. to install a new version.
+However, it should be used only on systems where the kernel can maintain clock
+compensation whilst not under \fBchronyd\fP\(cqs control (i.e. Linux, FreeBSD, NetBSD,
+Solaris, and macOS 10.13 or later).
+.RE
+.sp
+\fB\-R\fP
+.RS 4
+When this option is used, the \fBinitstepslew\fP
+directive and the \fBmakestep\fP directive used with
+a positive limit will be ignored. This option is useful when restarting
+\fBchronyd\fP and can be used in conjunction with the \fB\-r\fP option.
+.RE
+.sp
+\fB\-s\fP
+.RS 4
+This option will set the system clock from the computer\(cqs real\-time clock (RTC)
+or to the last modification time of the file specified by the
+\fBdriftfile\fP directive. Real\-time clocks are
+supported only on Linux.
+.sp
+If used in conjunction with the \fB\-r\fP flag, \fBchronyd\fP will attempt to preserve
+the old samples after setting the system clock from the RTC. This can be used
+to allow \fBchronyd\fP to perform long term averaging of the gain or loss rate
+across system reboots, and is useful for systems with intermittent access to
+network that are shut down when not in use. For this to work well, it relies
+on \fBchronyd\fP having been able to determine accurate statistics for the
+difference between the RTC and system clock last time the computer was on.
+.sp
+If the last modification time of the drift file is later than both the current
+time and the RTC time, the system time will be set to it to restore the time
+when \fBchronyd\fP was previously stopped. This is useful on computers that have no
+RTC or the RTC is broken (e.g. it has no battery).
+.RE
+.sp
+\fB\-t\fP \fItimeout\fP
+.RS 4
+This option sets a timeout (in seconds) after which \fBchronyd\fP will exit. If the
+clock is not synchronised, it will exit with a non\-zero status. This is useful
+with the \fB\-q\fP or \fB\-Q\fP option to shorten the maximum time waiting for
+measurements, or with the \fB\-r\fP option to limit the time when \fBchronyd\fP is
+running, but still allow it to adjust the frequency of the system clock.
+.RE
+.sp
+\fB\-u\fP \fIuser\fP
+.RS 4
+This option sets the name of the system user to which \fBchronyd\fP will switch
+after start in order to drop root privileges. It overrides the
+\fBuser\fP directive (default \fI@DEFAULT_USER@\fP).
+.sp
+On Linux, \fBchronyd\fP needs to be compiled with support for the \fBlibcap\fP library.
+On macOS, FreeBSD, NetBSD and Solaris \fBchronyd\fP 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.
+.RE
+.sp
+\fB\-F\fP \fIlevel\fP
+.RS 4
+This option configures a system call filter when \fBchronyd\fP is compiled with
+support for the Linux secure computing (seccomp) facility. In level 1 the
+process is killed when a forbidden system call is made, in level \-1 the SIGSYS
+signal is thrown instead and in level 0 the filter is disabled (default 0).
+.sp
+It\(cqs recommended to enable the filter only when it\(cqs known to work on the
+version of the system where \fBchrony\fP is installed as the filter needs to allow
+also system calls made from libraries that \fBchronyd\fP 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, \fBchronyd\fP could be
+killed even in normal operation.
+.RE
+.sp
+\fB\-P\fP \fIpriority\fP
+.RS 4
+On Linux, this option 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.
+.RE
+.sp
+\fB\-m\fP
+.RS 4
+This option will lock \fBchronyd\fP into RAM so that it will never be paged out.
+This mode is only supported on Linux.
+.RE
+.sp
+\fB\-x\fP
+.RS 4
+This option disables the control of the system clock. \fBchronyd\fP will not try to
+make any adjustments of the clock. It will assume the clock is free running and
+still track its offset and frequency relative to the estimated true time. This
+option allows \fBchronyd\fP to run without the capability to adjust or set the
+system clock (e.g. in some containers) in order to operate as an NTP server. It
+is not recommended to run \fBchronyd\fP (with or without \fB\-x\fP) when another process
+is controlling the system clock.
+.RE
+.sp
+\fB\-v\fP
+.RS 4
+With this option \fBchronyd\fP will print version number to the terminal and exit.
+.RE
+.SH "FILES"
+.sp
+\fI@SYSCONFDIR@/chrony.conf\fP
+.SH "SEE ALSO"
+.sp
+\fBchronyc(1)\fP, \fBchrony.conf(5)\fP
+.SH "BUGS"
+.sp
+For instructions on how to report bugs, please visit
+.URL "https://chrony.tuxfamily.org/" "" "."
+.SH "AUTHORS"
+.sp
+chrony was written by Richard Curnow, Miroslav Lichvar, and others.
\ No newline at end of file
diff --git a/chrony_3_3/doc/faq.adoc b/chrony_3_3/doc/faq.adoc
new file mode 100644
index 0000000..5bad34f
--- /dev/null
+++ b/chrony_3_3/doc/faq.adoc
@@ -0,0 +1,459 @@
+// This file is part of chrony
+//
+// Copyright (C) Richard P. Curnow  1997-2003
+// Copyright (C) Miroslav Lichvar  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.
+
+= Frequently Asked Questions
+:toc:
+:numbered:
+
+== `chrony` compared to other programs
+
+=== 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
+https://chrony.tuxfamily.org/comparison.html[comparison page] on the `chrony`
+website.
+
+== Configuration issues
+
+=== 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
+http://www.pool.ntp.org/[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
+----
+
+=== 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.
+
+=== 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
+
+* the load on the external connection is less
+* the load on the external NTP server(s) is less
+* if your external connection goes down, the computers on the LAN
+  will maintain a common time with each other.
+
+=== Must I specify servers by IP address if DNS is not available on chronyd start?
+
+No. Starting from version 1.25, `chronyd` will keep trying to resolve
+the 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.
+
+=== 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.
+
+=== 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).
+
+An example of the directive for an NTP server on the Internet that you are
+allowed to poll frequently could be
+
+----
+server foo.example.net minpoll 4 maxpoll 6 polltarget 16
+----
+
+An example using very short polling intervals for a server located in the same
+LAN could be
+
+----
+server ntp.local minpoll 2 maxpoll 4 polltarget 30
+----
+
+The maxdelay options are useful to ignore measurements with larger delay (e.g.
+due to congestion in the network) and improve the stability of the
+synchronisation. The `maxdelaydevratio` option could be added to the example
+with local NTP server
+
+----
+server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
+----
+
+If your server supports the interleaved mode, the `xleave` option should be
+added to the `server` directive in order to allow the server to send the
+client more accurate hardware or kernel transmit timestamps. When combined with
+local hardware timestamping, sub-microsecond accuracy may be possible. An
+example could be
+
+----
+server ntp.local minpoll 2 maxpoll 2 xleave
+hwtimestamp eth0
+----
+
+=== 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'
+----
+
+=== 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.
+
+== Computer is not synchronising
+
+This is the most common problem. There are a number of reasons, see the
+following questions.
+
+=== 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
+----
+
+=== 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
+----
+
+=== 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
+----
+
+== Issues with `chronyc`
+
+=== I keep getting the error `506 Cannot talk to daemon`
+
+When accessing `chronyd` remotely, make sure that the _chrony.conf_ file (on
+the computer where `chronyd` is running) has a `cmdallow` entry for the
+computer you are running `chronyc` on and an appropriate `bindcmdaddress`
+directive. This isn't necessary for localhost.
+
+Perhaps `chronyd` is not running. Try using the `ps` command (e.g. on Linux,
+`ps -auxw`) to see if it's running. Or try `netstat -a` and see if the ports
+123/udp and 323/udp are listening. If `chronyd` is not running, you may have a
+problem with the way you are trying to start it (e.g. at boot time).
+
+Perhaps you have a firewall set up in a way that blocks packets on port
+323/udp. You need to amend the firewall configuration in this case.
+
+=== 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).
+
+=== 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.
+
+=== Is the `chronyc` / `chronyd` protocol documented anywhere?
+
+Only by the source code. See _cmdmon.c_ (`chronyd` side) and _client.c_
+(`chronyc` side).
+
+== Real-time clock issues
+
+=== What is the real-time clock (RTC)?
+
+This is the clock which keeps the time even when your computer is turned off.
+It 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.
+
+=== 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.
+
+=== 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
+
+* an RTC in your computer
+* a Linux kernel with enabled RTC support
+* an `rtcfile` directive in your _chrony.conf_ file
+
+=== 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.
+
+=== 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.
+
+== NTP-specific issues
+
+=== 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.
+
+=== 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).
+
+=== 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.
+
+=== 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.
+
+== Operating systems
+
+=== Does `chrony` support Windows?
+
+No. The `chronyc` program (the command-line client used for configuring
+`chronyd` while it is running) has been successfully built and run under
+Cygwin in the past. `chronyd` is not portable, because part of it is
+very system-dependent. It needs adapting to work with Windows'
+equivalent of the adjtimex() call, and it needs to be made to work as a
+service.
+
+=== Are there any plans to support Windows?
+
+We have no plans to do this. Anyone is welcome to pick this work up and
+contribute it back to the project.
diff --git a/chrony_3_3/doc/installation.adoc b/chrony_3_3/doc/installation.adoc
new file mode 100644
index 0000000..eea9088
--- /dev/null
+++ b/chrony_3_3/doc/installation.adoc
@@ -0,0 +1,217 @@
+// This file is part of chrony
+//
+// Copyright (C) Richard P. Curnow  1997-2003
+// Copyright (C) Miroslav Lichvar  2009-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.
+
+= 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 https://www.lysator.liu.se/~nisse/nettle/[Nettle],
+https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS[NSS], or
+http://www.libtom.net/LibTomCrypt/[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
+http://linuxpps.org[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
+https://github.com/seccomp/libseccomp[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.
diff --git a/chrony_3_3/examples/chrony-wait.service b/chrony_3_3/examples/chrony-wait.service
new file mode 100644
index 0000000..0f5e2e7
--- /dev/null
+++ b/chrony_3_3/examples/chrony-wait.service
@@ -0,0 +1,18 @@
+[Unit]
+Description=Wait for chrony to synchronize system clock
+Documentation=man:chronyc(1)
+After=chronyd.service
+Requires=chronyd.service
+Before=time-sync.target
+Wants=time-sync.target
+
+[Service]
+Type=oneshot
+# Wait up to ~10 minutes for chronyd to synchronize and the remaining
+# clock correction to be less than 0.1 seconds
+ExecStart=/usr/bin/chronyc -h 127.0.0.1,::1 waitsync 600 0.1 0.0 1
+RemainAfterExit=yes
+StandardOutput=null
+
+[Install]
+WantedBy=multi-user.target
diff --git a/chrony_3_3/examples/chrony.conf.example1 b/chrony_3_3/examples/chrony.conf.example1
new file mode 100644
index 0000000..5e93ea7
--- /dev/null
+++ b/chrony_3_3/examples/chrony.conf.example1
@@ -0,0 +1,12 @@
+# Use public NTP servers from the pool.ntp.org project.
+pool pool.ntp.org iburst
+
+# Record the rate at which the system clock gains/losses time.
+driftfile /var/lib/chrony/drift
+
+# Allow the system clock to be stepped in the first three updates
+# if its offset is larger than 1 second.
+makestep 1.0 3
+
+# Enable kernel synchronization of the real-time clock (RTC).
+rtcsync
diff --git a/chrony_3_3/examples/chrony.conf.example2 b/chrony_3_3/examples/chrony.conf.example2
new file mode 100644
index 0000000..21be153
--- /dev/null
+++ b/chrony_3_3/examples/chrony.conf.example2
@@ -0,0 +1,38 @@
+# Use public servers from the pool.ntp.org project.
+# Please consider joining the pool (http://www.pool.ntp.org/join.html).
+pool pool.ntp.org iburst
+
+# Record the rate at which the system clock gains/losses time.
+driftfile /var/lib/chrony/drift
+
+# Allow the system clock to be stepped in the first three updates
+# if its offset is larger than 1 second.
+makestep 1.0 3
+
+# Enable kernel synchronization of the real-time clock (RTC).
+rtcsync
+
+# Enable hardware timestamping on all interfaces that support it.
+#hwtimestamp *
+
+# Increase the minimum number of selectable sources required to adjust
+# the system clock.
+#minsources 2
+
+# Allow NTP client access from local network.
+#allow 192.168.0.0/16
+
+# Serve time even if not synchronized to a time source.
+#local stratum 10
+
+# Specify file containing keys for NTP authentication.
+#keyfile /etc/chrony.keys
+
+# Get TAI-UTC offset and leap seconds from the system tz database.
+#leapsectz right/UTC
+
+# Specify directory for log files.
+logdir /var/log/chrony
+
+# Select which information is logged.
+#log measurements statistics tracking
diff --git a/chrony_3_3/examples/chrony.conf.example3 b/chrony_3_3/examples/chrony.conf.example3
new file mode 100644
index 0000000..05a4e98
--- /dev/null
+++ b/chrony_3_3/examples/chrony.conf.example3
@@ -0,0 +1,304 @@
+#######################################################################
+#
+# This is an example chrony configuration file.  You should copy it to
+# /etc/chrony.conf after uncommenting and editing the options that you
+# want to enable.  The more obscure options are not included.  Refer
+# to the documentation for these.
+#
+#######################################################################
+### COMMENTS
+# Any of the following lines are comments (you have a choice of
+# comment start character):
+# a comment
+% a comment
+! a comment
+; a comment
+#
+# Below, the '!' form is used for lines that you might want to
+# uncomment and edit to make your own chrony.conf file.
+#
+#######################################################################
+#######################################################################
+### SPECIFY YOUR NTP SERVERS
+# Most computers using chrony will send measurement requests to one or
+# more 'NTP servers'.  You will probably find that your Internet Service
+# Provider or company have one or more NTP servers that you can specify.
+# Failing that, there are a lot of public NTP servers.  There is a list
+# you can access at http://support.ntp.org/bin/view/Servers/WebHome or
+# you can use servers from the pool.ntp.org project.
+
+! server foo.example.net iburst
+! server bar.example.net iburst
+! server baz.example.net iburst
+
+! pool pool.ntp.org iburst
+ 
+#######################################################################
+### AVOIDING POTENTIALLY BOGUS CHANGES TO YOUR CLOCK
+#
+# To avoid changes being made to your computer's gain/loss compensation
+# when the measurement history is too erratic, you might want to enable
+# one of the following lines.  The first seems good with servers on the
+# Internet, the second seems OK for a LAN environment.
+
+! maxupdateskew 100
+! maxupdateskew 5
+
+# If you want to increase the minimum number of selectable sources
+# required to update the system clock in order to make the
+# synchronisation more reliable, uncomment (and edit) the following
+# line.
+
+! minsources 2
+
+# If your computer has a good stable clock (e.g. it is not a virtual
+# machine), you might also want to reduce the maximum assumed drift
+# (frequency error) of the clock (the value is specified in ppm).
+
+! maxdrift 100
+
+#######################################################################
+### FILENAMES ETC
+# Chrony likes to keep information about your computer's clock in files.
+# The 'driftfile' stores the computer's clock gain/loss rate in parts
+# per million.  When chronyd starts, the system clock can be tuned
+# immediately so that it doesn't gain or lose any more time.  You
+# generally want this, so it is uncommented.
+
+driftfile /var/lib/chrony/drift
+
+# If you want to enable NTP authentication with symmetric keys, you will need
+# to uncomment the following line and edit the file to set up the keys.
+
+! keyfile /etc/chrony.keys
+
+# chronyd can save the measurement history for the servers to files when
+# it it exits.  This is useful in 2 situations:
+#
+# 1. On Linux, if you stop chronyd and restart it with '-r' (e.g. after
+# an upgrade), the old measurements will still be relevant when chronyd
+# is restarted.  This will reduce the time needed to get accurate
+# gain/loss measurements, especially with a dial-up link.
+#
+# 2. Again on Linux, if you use the RTC support and start chronyd with
+# '-r -s' on bootup, measurements from the last boot will still be
+# useful (the real time clock is used to 'flywheel' chronyd between
+# boots).
+#
+# Enable these two options to use this.
+
+! dumponexit
+! dumpdir /var/lib/chrony
+
+# chronyd writes its process ID to a file.  If you try to start a second
+# copy of chronyd, it will detect that the process named in the file is
+# still running and bail out.  If you want to change the path to the PID
+# file, uncomment this line and edit it.  The default path is shown.
+
+! pidfile /var/run/chronyd.pid
+
+# If the system timezone database is kept up to date and includes the
+# right/UTC timezone, chronyd can use it to determine the current
+# TAI-UTC offset and when will the next leap second occur.
+
+! leapsectz right/UTC
+
+#######################################################################
+### INITIAL CLOCK CORRECTION
+# This option is useful to quickly correct the clock on start if it's
+# off by a large amount.  The value '1.0' means that if the error is less
+# than 1 second, it will be gradually removed by speeding up or slowing
+# down your computer's clock until it is correct.  If the error is above
+# 1 second, an immediate time jump will be applied to correct it.  The
+# value '3' means the step is allowed only in the first three updates of
+# the clock.  Some software can get upset if the system clock jumps
+# (especially backwards), so be careful!
+
+! makestep 1.0 3
+
+#######################################################################
+### LOGGING
+# If you want to log information about the time measurements chronyd has
+# gathered, you might want to enable the following lines.  You probably
+# only need this if you really enjoy looking at the logs, you want to
+# produce some graphs of your system's timekeeping performance, or you
+# need help in debugging a problem.
+
+! logdir /var/log/chrony
+! log measurements statistics tracking
+
+# If you have real time clock support enabled (see below), you might want
+# this line instead:
+
+! log measurements statistics tracking rtc
+
+#######################################################################
+### ACTING AS AN NTP SERVER
+# You might want the computer to be an NTP server for other computers.
+# e.g.  you might be running chronyd on a dial-up machine that has a LAN
+# sitting behind it with several 'satellite' computers on it.
+#
+# By default, chronyd does not allow any clients to access it.  You need
+# to explicitly enable access using 'allow' and 'deny' directives.
+#
+# e.g. to enable client access from the 192.168.*.* class B subnet,
+
+! allow 192.168/16
+
+# .. but disallow the 192.168.100.* subnet of that,
+
+! deny 192.168.100/24
+
+# You can have as many allow and deny directives as you need.  The order
+# is unimportant.
+
+# If you want chronyd to act as an NTP broadcast server, enable and edit
+# (and maybe copy) the following line.  This means that a broadcast
+# packet is sent to the address 192.168.1.255 every 60 seconds.  The
+# address MUST correspond to the broadcast address of one of the network
+# interfaces on your machine.  If you have multiple network interfaces,
+# add a broadcast line for each.
+
+! broadcast 60 192.168.1.255
+
+# If you want to present your computer's time for others to synchronise
+# with, even if you don't seem to be synchronised to any NTP servers
+# yourself, enable the following line.  The value 10 may be varied
+# between 1 and 15.  You should avoid small values because you will look
+# like a real NTP server.  The value 10 means that you appear to be 10
+# NTP 'hops' away from an authoritative source (atomic clock, GPS
+# receiver, radio clock etc).
+
+! local stratum 10
+
+# Normally, chronyd will keep track of how many times each client
+# machine accesses it.  The information can be accessed by the 'clients'
+# command of chronyc.  You can disable this facility by uncommenting the
+# following line.  This will save a bit of memory if you have many
+# clients and it will also disable support for the interleaved mode.
+
+! noclientlog
+
+# The clientlog size is limited to 512KB by default.  If you have many
+# clients, you might want to increase the limit.
+
+! clientloglimit 4194304
+
+# By default, chronyd tries to respond to all valid NTP requests from
+# allowed addresses.  If you want to limit the response rate for NTP
+# clients that are sending requests too frequently, uncomment and edit
+# the following line.
+
+! ratelimit interval 3 burst 8
+
+#######################################################################
+### REPORTING BIG CLOCK CHANGES
+# Perhaps you want to know if chronyd suddenly detects any large error
+# in your computer's clock.  This might indicate a fault or a problem
+# with the server(s) you are using, for example.
+#
+# The next option causes a message to be written to syslog when chronyd
+# has to correct an error above 0.5 seconds (you can use any amount you
+# like).
+
+! logchange 0.5
+
+# The next option will send email to the named person when chronyd has
+# to correct an error above 0.5 seconds.  (If you need to send mail to
+# several people, you need to set up a mailing list or sendmail alias
+# for them and use the address of that.)
+
+! mailonchange wibble@foo.example.net 0.5
+
+#######################################################################
+### COMMAND ACCESS
+# The program chronyc is used to show the current operation of chronyd
+# and to change parts of its configuration whilst it is running.
+
+# By default chronyd binds to the loopback interface.  Uncomment the
+# following lines to allow receiving command packets from remote hosts.
+
+! bindcmdaddress 0.0.0.0
+! bindcmdaddress ::
+
+# Normally, chronyd will only allow connections from chronyc on the same
+# machine as itself.  This is for security.  If you have a subnet
+# 192.168.*.* and you want to be able to use chronyc from any machine on
+# it, you could uncomment the following line.  (Edit this to your own
+# situation.)
+
+! cmdallow 192.168/16
+
+# You can add as many 'cmdallow' and 'cmddeny' lines as you like.  The
+# syntax and meaning is the same as for 'allow' and 'deny', except that
+# 'cmdallow' and 'cmddeny' control access to the chronyd's command port.
+
+# Rate limiting can be enabled also for command packets.  (Note,
+# commands from localhost are never limited.)
+
+! cmdratelimit interval -4 burst 16
+
+#######################################################################
+### HARDWARE TIMESTAMPING
+# On Linux, if the network interface controller and its driver support
+# hardware timestamping, it can significantly improve the accuracy of
+# synchronisation. It can be enabled on specified interfaces only, or it
+# can be enabled on all interfaces that support it.
+
+! hwtimestamp eth0
+! hwtimestamp *
+
+#######################################################################
+### REAL TIME CLOCK
+# chronyd can characterise the system's real-time clock.  This is the
+# clock that keeps running when the power is turned off, so that the
+# machine knows the approximate time when it boots again.  The error at
+# a particular epoch and gain/loss rate can be written to a file and
+# used later by chronyd when it is started with the '-s' option.
+#
+# You need to have 'enhanced RTC support' compiled into your Linux
+# kernel.  (Note, these options apply only to Linux.)
+
+! rtcfile /var/lib/chrony/rtc
+
+# Your RTC can be set to keep Universal Coordinated Time (UTC) or local
+# time.  (Local time means UTC +/- the effect of your timezone.)  If you
+# use UTC, chronyd will function correctly even if the computer is off
+# at the epoch when you enter or leave summer time (aka daylight saving
+# time).  However, if you dual boot your system with Microsoft Windows,
+# that will work better if your RTC maintains local time.  You take your
+# pick!
+
+! rtconutc
+
+# By default chronyd assumes that the enhanced RTC device is accessed as
+# /dev/rtc.  If it's accessed somewhere else on your system (e.g. you're
+# using devfs), uncomment and edit the following line.
+
+! rtcdevice /dev/misc/rtc
+
+# Alternatively, if not using the -s option, this directive can be used
+# to enable a mode in which the RTC is periodically set to the system
+# time, with no tracking of its drift.
+
+! rtcsync
+
+#######################################################################
+### REAL TIME SCHEDULER
+# This directive tells chronyd to use the real-time FIFO scheduler with the
+# specified priority (which must be between 0 and 100).  This should result
+# in reduced latency.  You don't need it unless you really have a requirement
+# for extreme clock stability.  Works only on Linux.  Note that the "-P"
+# command-line switch will override this.
+
+! sched_priority 1
+
+#######################################################################
+### LOCKING CHRONYD INTO RAM
+# This directive tells chronyd to use the mlockall() syscall to lock itself
+# into RAM so that it will never be paged out.  This should result in reduced
+# latency.  You don't need it unless you really have a requirement
+# for extreme clock stability.  Works only on Linux.  Note that the "-m"
+# command-line switch will also enable this feature.
+
+! lock_all
diff --git a/chrony_3_3/examples/chrony.keys.example b/chrony_3_3/examples/chrony.keys.example
new file mode 100644
index 0000000..2dd19cd
--- /dev/null
+++ b/chrony_3_3/examples/chrony.keys.example
@@ -0,0 +1,12 @@
+# This is an example chrony keys file.  It is used for NTP authentication with
+# symmetric keys.  It should be readable only by root or the user to which
+# chronyd is configured to switch to after start.
+#
+# Don't use the example keys!  It's recommended to generate random keys using
+# the chronyc keygen command.
+
+# Examples of valid keys:
+
+#1 MD5 AVeryLongAndRandomPassword
+#2 MD5 HEX:12114855C7931009B4049EF3EFC48A139C3F989F
+#3 SHA1 HEX:B2159C05D6A219673A3B7E896B6DE07F6A440995
diff --git a/chrony_3_3/examples/chrony.logrotate b/chrony_3_3/examples/chrony.logrotate
new file mode 100644
index 0000000..2823a1a
--- /dev/null
+++ b/chrony_3_3/examples/chrony.logrotate
@@ -0,0 +1,8 @@
+/var/log/chrony/*.log {
+    missingok
+    nocreate
+    sharedscripts
+    postrotate
+        /usr/bin/chronyc cyclelogs > /dev/null 2>&1 || true
+    endscript
+}
diff --git a/chrony_3_3/examples/chrony.nm-dispatcher b/chrony_3_3/examples/chrony.nm-dispatcher
new file mode 100644
index 0000000..a609a66
--- /dev/null
+++ b/chrony_3_3/examples/chrony.nm-dispatcher
@@ -0,0 +1,37 @@
+#!/bin/sh
+# This is a NetworkManager dispatcher script for chronyd to set its NTP sources
+# online or offline when a network interface is configured or removed
+
+export LC_ALL=C
+
+[ "$2" != "up" ] && [ "$2" != "down" ] && exit 0
+
+# Check if there is a default route
+
+if /sbin/ip route list 2> /dev/null | grep -q '^default'; then
+  chronyc online > /dev/null 2>&1
+  exit 0
+fi
+
+sources=$(chronyc -c -n sources 2> /dev/null)
+
+[ $? -ne 0 ] && exit 0
+
+# Check each configured source if it has a route
+
+echo "$sources" | while IFS=, read mode state address rest; do
+  [ "$mode" != '^' ] && [ "$mode" != '=' ] && continue
+
+  /sbin/ip route get "$address" > /dev/null 2>&1 && command="online" || command="offline"
+
+  # Set priority of sources so that the selected source is set as
+  # last if offline to avoid unnecessary reselection
+  [ "$state" != '*' ] && priority=1 || priority=2
+
+  echo "$priority $command $address"
+
+done | sort | while read priority command address; do
+  echo "$command $address"
+done | chronyc > /dev/null 2>&1
+
+exit 0
diff --git a/chrony_3_3/examples/chrony.spec b/chrony_3_3/examples/chrony.spec
new file mode 100644
index 0000000..8d03d09
--- /dev/null
+++ b/chrony_3_3/examples/chrony.spec
@@ -0,0 +1,46 @@
+%global chrony_version 3.3
+%if 0%(echo %{chrony_version} | grep -q pre && echo 1)
+%global prerelease %(echo %{chrony_version} | sed 's/.*-//')
+%endif
+Summary: An NTP client/server
+Name: chrony
+Version: %(echo %{chrony_version} | sed 's/-.*//')
+Release: %{!?prerelease:1}%{?prerelease:0.1.%{prerelease}}
+Source: chrony-%{version}%{?prerelease:-%{prerelease}}.tar.gz
+License: GPLv2
+Group: Applications/Utilities
+BuildRoot: %{_tmppath}/%{name}-%{version}-root-%(id -u -n)
+
+%description
+chrony is a client and server for the Network Time Protocol (NTP).
+This program keeps your computer's clock accurate. It was specially
+designed to support systems with intermittent Internet connections,
+but it also works well in permanently connected environments. It can
+also use hardware reference clocks, the system real-time clock, or
+manual input as time references.
+
+%prep
+%setup -q -n %{name}-%{version}%{?prerelease:-%{prerelease}}
+
+%build
+./configure \
+	--prefix=%{_prefix} \
+	--bindir=%{_bindir} \
+	--sbindir=%{_sbindir} \
+	--mandir=%{_mandir}
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+
+%files
+%{_sbindir}/chronyd
+%{_bindir}/chronyc
+%{_mandir}/man1/chronyc.1.gz
+%{_mandir}/man5/chrony.conf.5.gz
+%{_mandir}/man8/chronyd.8.gz
+%doc README FAQ NEWS COPYING
+%doc examples/chrony.conf.example*
+%doc examples/chrony.keys.example
+
diff --git a/chrony_3_3/examples/chronyd.service b/chrony_3_3/examples/chronyd.service
new file mode 100644
index 0000000..4ffe3b1
--- /dev/null
+++ b/chrony_3_3/examples/chronyd.service
@@ -0,0 +1,18 @@
+[Unit]
+Description=NTP client/server
+Documentation=man:chronyd(8) man:chrony.conf(5)
+After=ntpdate.service sntp.service ntpd.service
+Conflicts=ntpd.service systemd-timesyncd.service
+ConditionCapability=CAP_SYS_TIME
+
+[Service]
+Type=forking
+PIDFile=/var/run/chronyd.pid
+EnvironmentFile=-/etc/sysconfig/chronyd
+ExecStart=/usr/sbin/chronyd $OPTIONS
+PrivateTmp=yes
+ProtectHome=yes
+ProtectSystem=full
+
+[Install]
+WantedBy=multi-user.target
diff --git a/chrony_3_3/getdate.c b/chrony_3_3/getdate.c
new file mode 100644
index 0000000..c0c502a
--- /dev/null
+++ b/chrony_3_3/getdate.c
@@ -0,0 +1,2713 @@
+/* A Bison parser, made by GNU Bison 3.0.4.  */
+
+/* Bison implementation for Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
+   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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "3.0.4"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 1 "getdate.y" /* yacc.c:339  */
+
+/*
+**  Originally written by Steven M. Bellovin <smb@research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
+**
+**  This code is in the public domain and has no copyright.
+*/
+
+#include "config.h"
+
+/* Since the code of getdate.y is not included in the Emacs executable
+   itself, there is no need to #define static in this file.  Even if
+   the code were included in the Emacs executable, it probably
+   wouldn't do any harm to #undef it here; this will only cause
+   problems if we try to write to a static variable, which I don't
+   think this code needs to do.  */
+#ifdef emacs
+# undef static
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if HAVE_STDLIB_H
+# include <stdlib.h> /* for `free'; used by Bison 1.27 */
+#endif
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+
+/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
+   - Its arg may be any int or unsigned int; it need not be an unsigned char.
+   - It's guaranteed to evaluate its argument exactly once.
+   - It's typically faster.
+   Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+   only '0' through '9' are digits.  Prefer ISDIGIT to ISDIGIT_LOCALE unless
+   it's important to use the locale's definition of `digit' even when the
+   host does not conform to Posix.  */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#if defined (STDC_HEADERS) || defined (USG)
+# include <string.h>
+#endif
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+   That loses on systems that don't provide the function, so we have
+   to redefine it here.  */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+# define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+   as well as gratuitiously global symbol names, so we can have multiple
+   yacc generated parsers in the same program.  Note that these are only
+   the variables produced by yacc.  If other parser generators (bison,
+   byacc, etc) produce additional global names that conflict at link time,
+   then those parser generators need to be fixed instead of adding those
+   names to this list. */
+
+#define yymaxdepth gd_maxdepth
+#define yyparse gd_parse
+#define yylex   gd_lex
+#define yyerror gd_error
+#define yylval  gd_lval
+#define yychar  gd_char
+#define yydebug gd_debug
+#define yypact  gd_pact
+#define yyr1    gd_r1
+#define yyr2    gd_r2
+#define yydef   gd_def
+#define yychk   gd_chk
+#define yypgo   gd_pgo
+#define yyact   gd_act
+#define yyexca  gd_exca
+#define yyerrflag gd_errflag
+#define yynerrs gd_nerrs
+#define yyps    gd_ps
+#define yypv    gd_pv
+#define yys     gd_s
+#define yy_yys  gd_yys
+#define yystate gd_state
+#define yytmp   gd_tmp
+#define yyv     gd_v
+#define yy_yyv  gd_yyv
+#define yyval   gd_val
+#define yylloc  gd_lloc
+#define yyreds  gd_reds          /* With YYDEBUG defined */
+#define yytoks  gd_toks          /* With YYDEBUG defined */
+#define yylhs   gd_yylhs
+#define yylen   gd_yylen
+#define yydefred gd_yydefred
+#define yydgoto gd_yydgoto
+#define yysindex gd_yysindex
+#define yyrindex gd_yyrindex
+#define yygindex gd_yygindex
+#define yytable  gd_yytable
+#define yycheck  gd_yycheck
+
+static int yylex (void);
+static int yyerror (char *s);
+
+#define EPOCH		1970
+#define HOUR(x)		((x) * 60)
+
+#define MAX_BUFF_LEN    128   /* size of buffer to read the date into */
+
+/*
+**  An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+    const char	*name;
+    int		type;
+    int		value;
+} TABLE;
+
+
+/*
+**  Meridian:  am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+    MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+**  Global variables.  We could get rid of most of these by using a good
+**  union as the yacc stack.  (This routine was originally written before
+**  yacc had the %union construct.)  Maybe someday; right now we only use
+**  the %union very rarely.
+*/
+static const char	*yyInput;
+static int	yyDayOrdinal;
+static int	yyDayNumber;
+static int	yyHaveDate;
+static int	yyHaveDay;
+static int	yyHaveRel;
+static int	yyHaveTime;
+static int	yyHaveZone;
+static int	yyTimezone;
+static int	yyDay;
+static int	yyHour;
+static int	yyMinutes;
+static int	yyMonth;
+static int	yySeconds;
+static int	yyYear;
+static MERIDIAN	yyMeridian;
+static int	yyRelDay;
+static int	yyRelHour;
+static int	yyRelMinutes;
+static int	yyRelMonth;
+static int	yyRelSeconds;
+static int	yyRelYear;
+
+
+#line 239 "getdate.c" /* yacc.c:339  */
+
+# ifndef YY_NULLPTR
+#  if defined __cplusplus && 201103L <= __cplusplus
+#   define YY_NULLPTR nullptr
+#  else
+#   define YY_NULLPTR 0
+#  endif
+# endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+
+/* Debug traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token type.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+  enum yytokentype
+  {
+    tAGO = 258,
+    tDAY = 259,
+    tDAY_UNIT = 260,
+    tDAYZONE = 261,
+    tDST = 262,
+    tHOUR_UNIT = 263,
+    tID = 264,
+    tMERIDIAN = 265,
+    tMINUTE_UNIT = 266,
+    tMONTH = 267,
+    tMONTH_UNIT = 268,
+    tSEC_UNIT = 269,
+    tSNUMBER = 270,
+    tUNUMBER = 271,
+    tYEAR_UNIT = 272,
+    tZONE = 273
+  };
+#endif
+
+/* Value type.  */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+union YYSTYPE
+{
+#line 177 "getdate.y" /* yacc.c:355  */
+
+    int			Number;
+    enum _MERIDIAN	Meridian;
+
+#line 300 "getdate.c" /* yacc.c:355  */
+};
+
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE yylval;
+
+int yyparse (void);
+
+
+
+/* Copy the second part of user declarations.  */
+
+#line 317 "getdate.c" /* yacc.c:358  */
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__                                               \
+      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
+     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+#  define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+     && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+#  define _Noreturn __declspec (noreturn)
+# else
+#  define _Noreturn YY_ATTRIBUTE ((__noreturn__))
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+    _Pragma ("GCC diagnostic push") \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+    _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
+#     ifndef EXIT_SUCCESS
+#      define EXIT_SUCCESS 0
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's 'empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
+       && ! ((defined YYMALLOC || defined malloc) \
+             && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+         || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
+    do                                                                  \
+      {                                                                 \
+        YYSIZE_T yynewbytes;                                            \
+        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
+        Stack = &yyptr->Stack_alloc;                                    \
+        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                 \
+    while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(Dst, Src, Count) \
+      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+#  else
+#   define YYCOPY(Dst, Src, Count)              \
+      do                                        \
+        {                                       \
+          YYSIZE_T yyi;                         \
+          for (yyi = 0; yyi < (Count); yyi++)   \
+            (Dst)[yyi] = (Src)[yyi];            \
+        }                                       \
+      while (0)
+#  endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  2
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   50
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  22
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  11
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  51
+/* YYNSTATES -- Number of states.  */
+#define YYNSTATES  61
+
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+   by yylex, with out-of-bounds checking.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   273
+
+#define YYTRANSLATE(YYX)                                                \
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex, without out-of-bounds checking.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,    20,     2,     2,    21,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    19,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18
+};
+
+#if YYDEBUG
+  /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   193,   193,   194,   197,   200,   203,   206,   209,   212,
+     215,   221,   227,   236,   242,   254,   257,   261,   266,   270,
+     274,   280,   284,   302,   308,   314,   318,   323,   327,   334,
+     342,   345,   348,   351,   354,   357,   360,   363,   366,   369,
+     372,   375,   378,   381,   384,   387,   390,   393,   396,   401,
+     435,   438
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "tAGO", "tDAY", "tDAY_UNIT", "tDAYZONE",
+  "tDST", "tHOUR_UNIT", "tID", "tMERIDIAN", "tMINUTE_UNIT", "tMONTH",
+  "tMONTH_UNIT", "tSEC_UNIT", "tSNUMBER", "tUNUMBER", "tYEAR_UNIT",
+  "tZONE", "':'", "','", "'/'", "$accept", "spec", "item", "time", "zone",
+  "day", "date", "rel", "relunit", "number", "o_merid", YY_NULLPTR
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+   (internal) symbol number NUM (which must be that of a token).  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,    58,
+      44,    47
+};
+# endif
+
+#define YYPACT_NINF -20
+
+#define yypact_value_is_default(Yystate) \
+  (!!((Yystate) == (-20)))
+
+#define YYTABLE_NINF -1
+
+#define yytable_value_is_error(Yytable_value) \
+  0
+
+  /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+     STATE-NUM.  */
+static const yytype_int8 yypact[] =
+{
+     -20,     0,   -20,   -19,   -20,   -20,   -20,   -20,   -13,   -20,
+     -20,    30,    15,   -20,    14,   -20,   -20,   -20,   -20,   -20,
+     -20,    19,   -20,   -20,     4,   -20,   -20,   -20,   -20,   -20,
+     -20,   -20,   -20,   -20,   -20,   -20,    -6,   -20,   -20,    16,
+     -20,    17,    23,   -20,   -20,    24,   -20,   -20,   -20,    27,
+      28,   -20,   -20,   -20,    29,   -20,    32,    -8,   -20,   -20,
+     -20
+};
+
+  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+     Performed when YYTABLE does not specify something else to do.  Zero
+     means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       2,     0,     1,    18,    39,    16,    42,    45,     0,    36,
+      48,     0,    49,    33,    15,     3,     4,     5,     7,     6,
+       8,    30,     9,    19,    25,    38,    41,    44,    35,    47,
+      32,    20,    37,    40,    10,    43,    27,    34,    46,     0,
+      31,     0,     0,    17,    29,     0,    24,    28,    23,    50,
+      21,    26,    51,    12,     0,    11,     0,    50,    22,    14,
+      13
+};
+
+  /* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+     -20,   -20,   -20,   -20,   -20,   -20,   -20,   -20,   -20,   -20,
+      -7
+};
+
+  /* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     1,    15,    16,    17,    18,    19,    20,    21,    22,
+      55
+};
+
+  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+     positive, shift that token.  If negative, reduce the rule whose
+     number is the opposite.  If YYTABLE_NINF, syntax error.  */
+static const yytype_uint8 yytable[] =
+{
+       2,    23,    52,    24,     3,     4,     5,    59,     6,    46,
+      47,     7,     8,     9,    10,    11,    12,    13,    14,    31,
+      32,    43,    44,    33,    45,    34,    35,    36,    37,    38,
+      39,    48,    40,    49,    41,    25,    42,    52,    26,    50,
+      51,    27,    53,    28,    29,    57,    54,    30,    58,    56,
+      60
+};
+
+static const yytype_uint8 yycheck[] =
+{
+       0,    20,    10,    16,     4,     5,     6,    15,     8,    15,
+      16,    11,    12,    13,    14,    15,    16,    17,    18,     4,
+       5,     7,     3,     8,    20,    10,    11,    12,    13,    14,
+      15,    15,    17,    16,    19,     5,    21,    10,     8,    16,
+      16,    11,    15,    13,    14,    16,    19,    17,    16,    21,
+      57
+};
+
+  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+     symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    23,     0,     4,     5,     6,     8,    11,    12,    13,
+      14,    15,    16,    17,    18,    24,    25,    26,    27,    28,
+      29,    30,    31,    20,    16,     5,     8,    11,    13,    14,
+      17,     4,     5,     8,    10,    11,    12,    13,    14,    15,
+      17,    19,    21,     7,     3,    20,    15,    16,    15,    16,
+      16,    16,    10,    15,    19,    32,    21,    16,    16,    15,
+      32
+};
+
+  /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    22,    23,    23,    24,    24,    24,    24,    24,    24,
+      25,    25,    25,    25,    25,    26,    26,    26,    27,    27,
+      27,    28,    28,    28,    28,    28,    28,    28,    28,    29,
+      29,    30,    30,    30,    30,    30,    30,    30,    30,    30,
+      30,    30,    30,    30,    30,    30,    30,    30,    30,    31,
+      32,    32
+};
+
+  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     2,     1,     1,     1,     1,     1,     1,
+       2,     4,     4,     6,     6,     1,     1,     2,     1,     2,
+       2,     3,     5,     3,     3,     2,     4,     2,     3,     2,
+       1,     2,     2,     1,     2,     2,     1,     2,     2,     1,
+       2,     2,     1,     2,     2,     1,     2,     2,     1,     1,
+       0,     1
+};
+
+
+#define yyerrok         (yyerrstatus = 0)
+#define yyclearin       (yychar = YYEMPTY)
+#define YYEMPTY         (-2)
+#define YYEOF           0
+
+#define YYACCEPT        goto yyacceptlab
+#define YYABORT         goto yyabortlab
+#define YYERROR         goto yyerrorlab
+
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                  \
+do                                                              \
+  if (yychar == YYEMPTY)                                        \
+    {                                                           \
+      yychar = (Token);                                         \
+      yylval = (Value);                                         \
+      YYPOPSTACK (yylen);                                       \
+      yystate = *yyssp;                                         \
+      goto yybackup;                                            \
+    }                                                           \
+  else                                                          \
+    {                                                           \
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;                                                  \
+    }                                                           \
+while (0)
+
+/* Error token number */
+#define YYTERROR        1
+#define YYERRCODE       256
+
+
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                        \
+do {                                            \
+  if (yydebug)                                  \
+    YYFPRINTF Args;                             \
+} while (0)
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
+do {                                                                      \
+  if (yydebug)                                                            \
+    {                                                                     \
+      YYFPRINTF (stderr, "%s ", Title);                                   \
+      yy_symbol_print (stderr,                                            \
+                  Type, Value); \
+      YYFPRINTF (stderr, "\n");                                           \
+    }                                                                     \
+} while (0)
+
+
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT.  |
+`----------------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+{
+  FILE *yyo = yyoutput;
+  YYUSE (yyo);
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+  YYUSE (yytype);
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+{
+  YYFPRINTF (yyoutput, "%s %s (",
+             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)                            \
+do {                                                            \
+  if (yydebug)                                                  \
+    yy_stack_print ((Bottom), (Top));                           \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule)
+{
+  unsigned long int yylno = yyrline[yyrule];
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+             yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr,
+                       yystos[yyssp[yyi + 1 - yynrhs]],
+                       &(yyvsp[(yyi + 1) - (yynrhs)])
+                                              );
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)          \
+do {                                    \
+  if (yydebug)                          \
+    yy_reduce_print (yyssp, yyvsp, Rule); \
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+yystrlen (const char *yystr)
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+        switch (*++yyp)
+          {
+          case '\'':
+          case ',':
+            goto do_not_strip_quotes;
+
+          case '\\':
+            if (*++yyp != '\\')
+              goto do_not_strip_quotes;
+            /* Fall through.  */
+          default:
+            if (yyres)
+              yyres[yyn] = *yyp;
+            yyn++;
+            break;
+
+          case '"':
+            if (yyres)
+              yyres[yyn] = '\0';
+            return yyn;
+          }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
+
+   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+                yytype_int16 *yyssp, int yytoken)
+{
+  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
+  YYSIZE_T yysize = yysize0;
+  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = YY_NULLPTR;
+  /* Arguments of yyformat. */
+  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+  /* Number of reported tokens (one for the "unexpected", one per
+     "expected"). */
+  int yycount = 0;
+
+  /* There are many possibilities here to consider:
+     - If this state is a consistent state with a default action, then
+       the only way this function was invoked is if the default action
+       is an error action.  In that case, don't check for expected
+       tokens because there are none.
+     - The only way there can be no lookahead present (in yychar) is if
+       this state is a consistent state with a default action.  Thus,
+       detecting the absence of a lookahead is sufficient to determine
+       that there is no unexpected or expected token to report.  In that
+       case, just report a simple "syntax error".
+     - Don't assume there isn't a lookahead just because this state is a
+       consistent state with a default action.  There might have been a
+       previous inconsistent state, consistent state with a non-default
+       action, or user semantic action that manipulated yychar.
+     - Of course, the expected token list depends on states to have
+       correct lookahead information, and it depends on the parser not
+       to perform extra reductions after fetching a lookahead from the
+       scanner and before detecting a syntax error.  Thus, state merging
+       (from LALR or IELR) and default reductions corrupt the expected
+       token list.  However, the list is correct for canonical LR with
+       one exception: it will still contain any token that will not be
+       accepted due to an error action in a later state.
+  */
+  if (yytoken != YYEMPTY)
+    {
+      int yyn = yypact[*yyssp];
+      yyarg[yycount++] = yytname[yytoken];
+      if (!yypact_value_is_default (yyn))
+        {
+          /* Start YYX at -YYN if negative to avoid negative indexes in
+             YYCHECK.  In other words, skip the first -YYN actions for
+             this state because they are default actions.  */
+          int yyxbegin = yyn < 0 ? -yyn : 0;
+          /* Stay within bounds of both yycheck and yytname.  */
+          int yychecklim = YYLAST - yyn + 1;
+          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+          int yyx;
+
+          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+                && !yytable_value_is_error (yytable[yyx + yyn]))
+              {
+                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+                  {
+                    yycount = 1;
+                    yysize = yysize0;
+                    break;
+                  }
+                yyarg[yycount++] = yytname[yyx];
+                {
+                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+                  if (! (yysize <= yysize1
+                         && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+                    return 2;
+                  yysize = yysize1;
+                }
+              }
+        }
+    }
+
+  switch (yycount)
+    {
+# define YYCASE_(N, S)                      \
+      case N:                               \
+        yyformat = S;                       \
+      break
+      YYCASE_(0, YY_("syntax error"));
+      YYCASE_(1, YY_("syntax error, unexpected %s"));
+      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+    }
+
+  {
+    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+    if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+      return 2;
+    yysize = yysize1;
+  }
+
+  if (*yymsg_alloc < yysize)
+    {
+      *yymsg_alloc = 2 * yysize;
+      if (! (yysize <= *yymsg_alloc
+             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+      return 1;
+    }
+
+  /* Avoid sprintf, as that infringes on the user's name space.
+     Don't have undefined behavior even if the translation
+     produced a string with the wrong number of "%s"s.  */
+  {
+    char *yyp = *yymsg;
+    int yyi = 0;
+    while ((*yyp = *yyformat) != '\0')
+      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+        {
+          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyformat += 2;
+        }
+      else
+        {
+          yyp++;
+          yyformat++;
+        }
+  }
+  return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+{
+  YYUSE (yyvaluep);
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  YYUSE (yytype);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+int
+yyparse (void)
+{
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       'yyss': related to states.
+       'yyvs': related to semantic values.
+
+       Refer to the stacks through separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yyssp = yyss = yyssa;
+  yyvsp = yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+        /* Give user a chance to reallocate the stack.  Use copies of
+           these so that the &'s don't force the real ones into
+           memory.  */
+        YYSTYPE *yyvs1 = yyvs;
+        yytype_int16 *yyss1 = yyss;
+
+        /* Each stack pointer address is followed by the size of the
+           data in use in that stack, in bytes.  This used to be a
+           conditional around just the two extra args, but that might
+           be undefined if yyoverflow is a macro.  */
+        yyoverflow (YY_("memory exhausted"),
+                    &yyss1, yysize * sizeof (*yyssp),
+                    &yyvs1, yysize * sizeof (*yyvsp),
+                    &yystacksize);
+
+        yyss = yyss1;
+        yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+        goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+        yystacksize = YYMAXDEPTH;
+
+      {
+        yytype_int16 *yyss1 = yyss;
+        union yyalloc *yyptr =
+          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+        if (! yyptr)
+          goto yyexhaustedlab;
+        YYSTACK_RELOCATE (yyss_alloc, yyss);
+        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+        if (yyss1 != yyssa)
+          YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+                  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+        YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yypact_value_is_default (yyn))
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = yylex ();
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yytable_value_is_error (yyn))
+        goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     '$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 4:
+#line 197 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyHaveTime++;
+	}
+#line 1436 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 5:
+#line 200 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyHaveZone++;
+	}
+#line 1444 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 6:
+#line 203 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyHaveDate++;
+	}
+#line 1452 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 7:
+#line 206 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyHaveDay++;
+	}
+#line 1460 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 8:
+#line 209 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyHaveRel++;
+	}
+#line 1468 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 10:
+#line 215 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyHour = (yyvsp[-1].Number);
+	    yyMinutes = 0;
+	    yySeconds = 0;
+	    yyMeridian = (yyvsp[0].Meridian);
+	}
+#line 1479 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 11:
+#line 221 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyHour = (yyvsp[-3].Number);
+	    yyMinutes = (yyvsp[-1].Number);
+	    yySeconds = 0;
+	    yyMeridian = (yyvsp[0].Meridian);
+	}
+#line 1490 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 12:
+#line 227 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyHour = (yyvsp[-3].Number);
+	    yyMinutes = (yyvsp[-1].Number);
+	    yyMeridian = MER24;
+	    yyHaveZone++;
+	    yyTimezone = ((yyvsp[0].Number) < 0
+			  ? -(yyvsp[0].Number) % 100 + (-(yyvsp[0].Number) / 100) * 60
+			  : - ((yyvsp[0].Number) % 100 + ((yyvsp[0].Number) / 100) * 60));
+	}
+#line 1504 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 13:
+#line 236 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyHour = (yyvsp[-5].Number);
+	    yyMinutes = (yyvsp[-3].Number);
+	    yySeconds = (yyvsp[-1].Number);
+	    yyMeridian = (yyvsp[0].Meridian);
+	}
+#line 1515 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 14:
+#line 242 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyHour = (yyvsp[-5].Number);
+	    yyMinutes = (yyvsp[-3].Number);
+	    yySeconds = (yyvsp[-1].Number);
+	    yyMeridian = MER24;
+	    yyHaveZone++;
+	    yyTimezone = ((yyvsp[0].Number) < 0
+			  ? -(yyvsp[0].Number) % 100 + (-(yyvsp[0].Number) / 100) * 60
+			  : - ((yyvsp[0].Number) % 100 + ((yyvsp[0].Number) / 100) * 60));
+	}
+#line 1530 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 15:
+#line 254 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyTimezone = (yyvsp[0].Number);
+	}
+#line 1538 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 16:
+#line 257 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyTimezone = (yyvsp[0].Number) - 60;
+	}
+#line 1546 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 17:
+#line 261 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyTimezone = (yyvsp[-1].Number) - 60;
+	}
+#line 1554 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 18:
+#line 266 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyDayOrdinal = 1;
+	    yyDayNumber = (yyvsp[0].Number);
+	}
+#line 1563 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 19:
+#line 270 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyDayOrdinal = 1;
+	    yyDayNumber = (yyvsp[-1].Number);
+	}
+#line 1572 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 20:
+#line 274 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyDayOrdinal = (yyvsp[-1].Number);
+	    yyDayNumber = (yyvsp[0].Number);
+	}
+#line 1581 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 21:
+#line 280 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyMonth = (yyvsp[-2].Number);
+	    yyDay = (yyvsp[0].Number);
+	}
+#line 1590 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 22:
+#line 284 "getdate.y" /* yacc.c:1646  */
+    {
+	  /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
+	     The goal in recognizing YYYY/MM/DD is solely to support legacy
+	     machine-generated dates like those in an RCS log listing.  If
+	     you want portability, use the ISO 8601 format.  */
+	  if ((yyvsp[-4].Number) >= 1000)
+	    {
+	      yyYear = (yyvsp[-4].Number);
+	      yyMonth = (yyvsp[-2].Number);
+	      yyDay = (yyvsp[0].Number);
+	    }
+	  else
+	    {
+	      yyMonth = (yyvsp[-4].Number);
+	      yyDay = (yyvsp[-2].Number);
+	      yyYear = (yyvsp[0].Number);
+	    }
+	}
+#line 1613 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 23:
+#line 302 "getdate.y" /* yacc.c:1646  */
+    {
+	    /* ISO 8601 format.  yyyy-mm-dd.  */
+	    yyYear = (yyvsp[-2].Number);
+	    yyMonth = -(yyvsp[-1].Number);
+	    yyDay = -(yyvsp[0].Number);
+	}
+#line 1624 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 24:
+#line 308 "getdate.y" /* yacc.c:1646  */
+    {
+	    /* e.g. 17-JUN-1992.  */
+	    yyDay = (yyvsp[-2].Number);
+	    yyMonth = (yyvsp[-1].Number);
+	    yyYear = -(yyvsp[0].Number);
+	}
+#line 1635 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 25:
+#line 314 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyMonth = (yyvsp[-1].Number);
+	    yyDay = (yyvsp[0].Number);
+	}
+#line 1644 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 26:
+#line 318 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyMonth = (yyvsp[-3].Number);
+	    yyDay = (yyvsp[-2].Number);
+	    yyYear = (yyvsp[0].Number);
+	}
+#line 1654 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 27:
+#line 323 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyMonth = (yyvsp[0].Number);
+	    yyDay = (yyvsp[-1].Number);
+	}
+#line 1663 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 28:
+#line 327 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyMonth = (yyvsp[-1].Number);
+	    yyDay = (yyvsp[-2].Number);
+	    yyYear = (yyvsp[0].Number);
+	}
+#line 1673 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 29:
+#line 334 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelSeconds = -yyRelSeconds;
+	    yyRelMinutes = -yyRelMinutes;
+	    yyRelHour = -yyRelHour;
+	    yyRelDay = -yyRelDay;
+	    yyRelMonth = -yyRelMonth;
+	    yyRelYear = -yyRelYear;
+	}
+#line 1686 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 31:
+#line 345 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelYear += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1694 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 32:
+#line 348 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelYear += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1702 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 33:
+#line 351 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelYear += (yyvsp[0].Number);
+	}
+#line 1710 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 34:
+#line 354 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelMonth += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1718 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 35:
+#line 357 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelMonth += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1726 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 36:
+#line 360 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelMonth += (yyvsp[0].Number);
+	}
+#line 1734 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 37:
+#line 363 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelDay += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1742 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 38:
+#line 366 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelDay += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1750 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 39:
+#line 369 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelDay += (yyvsp[0].Number);
+	}
+#line 1758 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 40:
+#line 372 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelHour += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1766 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 41:
+#line 375 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelHour += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1774 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 42:
+#line 378 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelHour += (yyvsp[0].Number);
+	}
+#line 1782 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 43:
+#line 381 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelMinutes += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1790 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 44:
+#line 384 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelMinutes += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1798 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 45:
+#line 387 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelMinutes += (yyvsp[0].Number);
+	}
+#line 1806 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 46:
+#line 390 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelSeconds += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1814 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 47:
+#line 393 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelSeconds += (yyvsp[-1].Number) * (yyvsp[0].Number);
+	}
+#line 1822 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 48:
+#line 396 "getdate.y" /* yacc.c:1646  */
+    {
+	    yyRelSeconds += (yyvsp[0].Number);
+	}
+#line 1830 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 49:
+#line 402 "getdate.y" /* yacc.c:1646  */
+    {
+	    if (yyHaveTime && yyHaveDate && !yyHaveRel)
+	      yyYear = (yyvsp[0].Number);
+	    else
+	      {
+		if ((yyvsp[0].Number)>10000)
+		  {
+		    yyHaveDate++;
+		    yyDay= ((yyvsp[0].Number))%100;
+		    yyMonth= ((yyvsp[0].Number)/100)%100;
+		    yyYear = (yyvsp[0].Number)/10000;
+		  }
+		else
+		  {
+		    yyHaveTime++;
+		    if ((yyvsp[0].Number) < 100)
+		      {
+			yyHour = (yyvsp[0].Number);
+			yyMinutes = 0;
+		      }
+		    else
+		      {
+		    	yyHour = (yyvsp[0].Number) / 100;
+		    	yyMinutes = (yyvsp[0].Number) % 100;
+		      }
+		    yySeconds = 0;
+		    yyMeridian = MER24;
+		  }
+	      }
+	  }
+#line 1865 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 50:
+#line 435 "getdate.y" /* yacc.c:1646  */
+    {
+	    (yyval.Meridian) = MER24;
+	  }
+#line 1873 "getdate.c" /* yacc.c:1646  */
+    break;
+
+  case 51:
+#line 439 "getdate.y" /* yacc.c:1646  */
+    {
+	    (yyval.Meridian) = (yyvsp[0].Meridian);
+	  }
+#line 1881 "getdate.c" /* yacc.c:1646  */
+    break;
+
+
+#line 1885 "getdate.c" /* yacc.c:1646  */
+      default: break;
+    }
+  /* User semantic actions sometimes alter yychar, and that requires
+     that yytoken be updated with the new translation.  We take the
+     approach of translating immediately before every use of yytoken.
+     One alternative is translating here after every semantic action,
+     but that translation would be missed if the semantic action invokes
+     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
+     incorrect destructor might then be invoked immediately.  In the
+     case of YYERROR or YYBACKUP, subsequent parser actions might lead
+     to an incorrect destructor call or verbose syntax error message
+     before the lookahead is translated.  */
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+  /* Now 'shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error.  |
+`--------------------------------------*/
+yyerrlab:
+  /* Make sure we have latest lookahead translation.  See comments at
+     user semantic actions for why this is necessary.  */
+  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+                                        yyssp, yytoken)
+      {
+        char const *yymsgp = YY_("syntax error");
+        int yysyntax_error_status;
+        yysyntax_error_status = YYSYNTAX_ERROR;
+        if (yysyntax_error_status == 0)
+          yymsgp = yymsg;
+        else if (yysyntax_error_status == 1)
+          {
+            if (yymsg != yymsgbuf)
+              YYSTACK_FREE (yymsg);
+            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+            if (!yymsg)
+              {
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = 2;
+              }
+            else
+              {
+                yysyntax_error_status = YYSYNTAX_ERROR;
+                yymsgp = yymsg;
+              }
+          }
+        yyerror (yymsgp);
+        if (yysyntax_error_status == 2)
+          goto yyexhaustedlab;
+      }
+# undef YYSYNTAX_ERROR
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+         error, discard it.  */
+
+      if (yychar <= YYEOF)
+        {
+          /* Return failure if at end of input.  */
+          if (yychar == YYEOF)
+            YYABORT;
+        }
+      else
+        {
+          yydestruct ("Error: discarding",
+                      yytoken, &yylval);
+          yychar = YYEMPTY;
+        }
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (!yypact_value_is_default (yyn))
+        {
+          yyn += YYTERROR;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+            {
+              yyn = yytable[yyn];
+              if (0 < yyn)
+                break;
+            }
+        }
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+        YYABORT;
+
+
+      yydestruct ("Error: popping",
+                  yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEMPTY)
+    {
+      /* Make sure we have latest lookahead translation.  See comments at
+         user semantic actions for why this is necessary.  */
+      yytoken = YYTRANSLATE (yychar);
+      yydestruct ("Cleanup: discarding lookahead",
+                  yytoken, &yylval);
+    }
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+                  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  return yyresult;
+}
+#line 444 "getdate.y" /* yacc.c:1906  */
+
+
+/* Include this file down here because bison inserts code above which
+   may define-away `const'.  We want the prototype for get_date to have
+   the same signature as the function definition does. */
+#include "getdate.h"
+
+extern struct tm	*gmtime ();
+extern struct tm	*localtime ();
+extern time_t		mktime ();
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+    { "january",	tMONTH,  1 },
+    { "february",	tMONTH,  2 },
+    { "march",		tMONTH,  3 },
+    { "april",		tMONTH,  4 },
+    { "may",		tMONTH,  5 },
+    { "june",		tMONTH,  6 },
+    { "july",		tMONTH,  7 },
+    { "august",		tMONTH,  8 },
+    { "september",	tMONTH,  9 },
+    { "sept",		tMONTH,  9 },
+    { "october",	tMONTH, 10 },
+    { "november",	tMONTH, 11 },
+    { "december",	tMONTH, 12 },
+    { "sunday",		tDAY, 0 },
+    { "monday",		tDAY, 1 },
+    { "tuesday",	tDAY, 2 },
+    { "tues",		tDAY, 2 },
+    { "wednesday",	tDAY, 3 },
+    { "wednes",		tDAY, 3 },
+    { "thursday",	tDAY, 4 },
+    { "thur",		tDAY, 4 },
+    { "thurs",		tDAY, 4 },
+    { "friday",		tDAY, 5 },
+    { "saturday",	tDAY, 6 },
+    { NULL, 0, 0 }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+    { "year",		tYEAR_UNIT,	1 },
+    { "month",		tMONTH_UNIT,	1 },
+    { "fortnight",	tDAY_UNIT,	14 },
+    { "week",		tDAY_UNIT,	7 },
+    { "day",		tDAY_UNIT,	1 },
+    { "hour",		tHOUR_UNIT,	1 },
+    { "minute",		tMINUTE_UNIT,	1 },
+    { "min",		tMINUTE_UNIT,	1 },
+    { "second",		tSEC_UNIT,	1 },
+    { "sec",		tSEC_UNIT,	1 },
+    { NULL, 0, 0 }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+    { "tomorrow",	tMINUTE_UNIT,	1 * 24 * 60 },
+    { "yesterday",	tMINUTE_UNIT,	-1 * 24 * 60 },
+    { "today",		tMINUTE_UNIT,	0 },
+    { "now",		tMINUTE_UNIT,	0 },
+    { "last",		tUNUMBER,	-1 },
+    { "this",		tMINUTE_UNIT,	0 },
+    { "next",		tUNUMBER,	1 },
+    { "first",		tUNUMBER,	1 },
+/*  { "second",		tUNUMBER,	2 }, */
+    { "third",		tUNUMBER,	3 },
+    { "fourth",		tUNUMBER,	4 },
+    { "fifth",		tUNUMBER,	5 },
+    { "sixth",		tUNUMBER,	6 },
+    { "seventh",	tUNUMBER,	7 },
+    { "eighth",		tUNUMBER,	8 },
+    { "ninth",		tUNUMBER,	9 },
+    { "tenth",		tUNUMBER,	10 },
+    { "eleventh",	tUNUMBER,	11 },
+    { "twelfth",	tUNUMBER,	12 },
+    { "ago",		tAGO,	1 },
+    { NULL, 0, 0 }
+};
+
+/* The timezone table. */
+static TABLE const TimezoneTable[] = {
+    { "gmt",	tZONE,     HOUR ( 0) },	/* Greenwich Mean */
+    { "ut",	tZONE,     HOUR ( 0) },	/* Universal (Coordinated) */
+    { "utc",	tZONE,     HOUR ( 0) },
+    { "wet",	tZONE,     HOUR ( 0) },	/* Western European */
+    { "bst",	tDAYZONE,  HOUR ( 0) },	/* British Summer */
+    { "wat",	tZONE,     HOUR ( 1) },	/* West Africa */
+    { "at",	tZONE,     HOUR ( 2) },	/* Azores */
+#if	0
+    /* For completeness.  BST is also British Summer, and GST is
+     * also Guam Standard. */
+    { "bst",	tZONE,     HOUR ( 3) },	/* Brazil Standard */
+    { "gst",	tZONE,     HOUR ( 3) },	/* Greenland Standard */
+#endif
+#if 0
+    { "nft",	tZONE,     HOUR (3.5) },	/* Newfoundland */
+    { "nst",	tZONE,     HOUR (3.5) },	/* Newfoundland Standard */
+    { "ndt",	tDAYZONE,  HOUR (3.5) },	/* Newfoundland Daylight */
+#endif
+    { "ast",	tZONE,     HOUR ( 4) },	/* Atlantic Standard */
+    { "adt",	tDAYZONE,  HOUR ( 4) },	/* Atlantic Daylight */
+    { "est",	tZONE,     HOUR ( 5) },	/* Eastern Standard */
+    { "edt",	tDAYZONE,  HOUR ( 5) },	/* Eastern Daylight */
+    { "cst",	tZONE,     HOUR ( 6) },	/* Central Standard */
+    { "cdt",	tDAYZONE,  HOUR ( 6) },	/* Central Daylight */
+    { "mst",	tZONE,     HOUR ( 7) },	/* Mountain Standard */
+    { "mdt",	tDAYZONE,  HOUR ( 7) },	/* Mountain Daylight */
+    { "pst",	tZONE,     HOUR ( 8) },	/* Pacific Standard */
+    { "pdt",	tDAYZONE,  HOUR ( 8) },	/* Pacific Daylight */
+    { "yst",	tZONE,     HOUR ( 9) },	/* Yukon Standard */
+    { "ydt",	tDAYZONE,  HOUR ( 9) },	/* Yukon Daylight */
+    { "hst",	tZONE,     HOUR (10) },	/* Hawaii Standard */
+    { "hdt",	tDAYZONE,  HOUR (10) },	/* Hawaii Daylight */
+    { "cat",	tZONE,     HOUR (10) },	/* Central Alaska */
+    { "ahst",	tZONE,     HOUR (10) },	/* Alaska-Hawaii Standard */
+    { "nt",	tZONE,     HOUR (11) },	/* Nome */
+    { "idlw",	tZONE,     HOUR (12) },	/* International Date Line West */
+    { "cet",	tZONE,     -HOUR (1) },	/* Central European */
+    { "met",	tZONE,     -HOUR (1) },	/* Middle European */
+    { "mewt",	tZONE,     -HOUR (1) },	/* Middle European Winter */
+    { "mest",	tDAYZONE,  -HOUR (1) },	/* Middle European Summer */
+    { "mesz",	tDAYZONE,  -HOUR (1) },	/* Middle European Summer */
+    { "swt",	tZONE,     -HOUR (1) },	/* Swedish Winter */
+    { "sst",	tDAYZONE,  -HOUR (1) },	/* Swedish Summer */
+    { "fwt",	tZONE,     -HOUR (1) },	/* French Winter */
+    { "fst",	tDAYZONE,  -HOUR (1) },	/* French Summer */
+    { "eet",	tZONE,     -HOUR (2) },	/* Eastern Europe, USSR Zone 1 */
+    { "bt",	tZONE,     -HOUR (3) },	/* Baghdad, USSR Zone 2 */
+#if 0
+    { "it",	tZONE,     -HOUR (3.5) },/* Iran */
+#endif
+    { "zp4",	tZONE,     -HOUR (4) },	/* USSR Zone 3 */
+    { "zp5",	tZONE,     -HOUR (5) },	/* USSR Zone 4 */
+#if 0
+    { "ist",	tZONE,     -HOUR (5.5) },/* Indian Standard */
+#endif
+    { "zp6",	tZONE,     -HOUR (6) },	/* USSR Zone 5 */
+#if	0
+    /* For completeness.  NST is also Newfoundland Standard, and SST is
+     * also Swedish Summer. */
+    { "nst",	tZONE,     -HOUR (6.5) },/* North Sumatra */
+    { "sst",	tZONE,     -HOUR (7) },	/* South Sumatra, USSR Zone 6 */
+#endif	/* 0 */
+    { "wast",	tZONE,     -HOUR (7) },	/* West Australian Standard */
+    { "wadt",	tDAYZONE,  -HOUR (7) },	/* West Australian Daylight */
+#if 0
+    { "jt",	tZONE,     -HOUR (7.5) },/* Java (3pm in Cronusland!) */
+#endif
+    { "cct",	tZONE,     -HOUR (8) },	/* China Coast, USSR Zone 7 */
+    { "jst",	tZONE,     -HOUR (9) },	/* Japan Standard, USSR Zone 8 */
+#if 0
+    { "cast",	tZONE,     -HOUR (9.5) },/* Central Australian Standard */
+    { "cadt",	tDAYZONE,  -HOUR (9.5) },/* Central Australian Daylight */
+#endif
+    { "east",	tZONE,     -HOUR (10) },	/* Eastern Australian Standard */
+    { "eadt",	tDAYZONE,  -HOUR (10) },	/* Eastern Australian Daylight */
+    { "gst",	tZONE,     -HOUR (10) },	/* Guam Standard, USSR Zone 9 */
+    { "nzt",	tZONE,     -HOUR (12) },	/* New Zealand */
+    { "nzst",	tZONE,     -HOUR (12) },	/* New Zealand Standard */
+    { "nzdt",	tDAYZONE,  -HOUR (12) },	/* New Zealand Daylight */
+    { "idle",	tZONE,     -HOUR (12) },	/* International Date Line East */
+    {  NULL, 0, 0  }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+    { "a",	tZONE,	HOUR (  1) },
+    { "b",	tZONE,	HOUR (  2) },
+    { "c",	tZONE,	HOUR (  3) },
+    { "d",	tZONE,	HOUR (  4) },
+    { "e",	tZONE,	HOUR (  5) },
+    { "f",	tZONE,	HOUR (  6) },
+    { "g",	tZONE,	HOUR (  7) },
+    { "h",	tZONE,	HOUR (  8) },
+    { "i",	tZONE,	HOUR (  9) },
+    { "k",	tZONE,	HOUR ( 10) },
+    { "l",	tZONE,	HOUR ( 11) },
+    { "m",	tZONE,	HOUR ( 12) },
+    { "n",	tZONE,	HOUR (- 1) },
+    { "o",	tZONE,	HOUR (- 2) },
+    { "p",	tZONE,	HOUR (- 3) },
+    { "q",	tZONE,	HOUR (- 4) },
+    { "r",	tZONE,	HOUR (- 5) },
+    { "s",	tZONE,	HOUR (- 6) },
+    { "t",	tZONE,	HOUR (- 7) },
+    { "u",	tZONE,	HOUR (- 8) },
+    { "v",	tZONE,	HOUR (- 9) },
+    { "w",	tZONE,	HOUR (-10) },
+    { "x",	tZONE,	HOUR (-11) },
+    { "y",	tZONE,	HOUR (-12) },
+    { "z",	tZONE,	HOUR (  0) },
+    { NULL, 0, 0 }
+};
+
+
+
+
+/* ARGSUSED */
+static int
+yyerror (s)
+     char *s ATTRIBUTE_UNUSED;
+{
+  return 0;
+}
+
+static int
+ToHour (Hours, Meridian)
+     int Hours;
+     MERIDIAN Meridian;
+{
+  switch (Meridian)
+    {
+    case MER24:
+      if (Hours < 0 || Hours > 23)
+	return -1;
+      return Hours;
+    case MERam:
+      if (Hours < 1 || Hours > 12)
+	return -1;
+      if (Hours == 12)
+	Hours = 0;
+      return Hours;
+    case MERpm:
+      if (Hours < 1 || Hours > 12)
+	return -1;
+      if (Hours == 12)
+	Hours = 0;
+      return Hours + 12;
+    default:
+      abort ();
+    }
+  /* NOTREACHED */
+}
+
+static int
+ToYear (Year)
+     int Year;
+{
+  if (Year < 0)
+    Year = -Year;
+
+  /* XPG4 suggests that years 00-68 map to 2000-2068, and
+     years 69-99 map to 1969-1999.  */
+  if (Year < 69)
+    Year += 2000;
+  else if (Year < 100)
+    Year += 1900;
+
+  return Year;
+}
+
+static int
+LookupWord (buff)
+     char *buff;
+{
+  register char *p;
+  register char *q;
+  register const TABLE *tp;
+  int i;
+  int abbrev;
+
+  /* Make it lowercase. */
+  for (p = buff; *p; p++)
+    if (ISUPPER ((unsigned char) *p))
+      *p = tolower ((unsigned char) *p);
+
+  if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
+    {
+      yylval.Meridian = MERam;
+      return tMERIDIAN;
+    }
+  if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0)
+    {
+      yylval.Meridian = MERpm;
+      return tMERIDIAN;
+    }
+
+  /* See if we have an abbreviation for a month. */
+  if (strlen (buff) == 3)
+    abbrev = 1;
+  else if (strlen (buff) == 4 && buff[3] == '.')
+    {
+      abbrev = 1;
+      buff[3] = '\0';
+    }
+  else
+    abbrev = 0;
+
+  for (tp = MonthDayTable; tp->name; tp++)
+    {
+      if (abbrev)
+	{
+	  if (strncmp (buff, tp->name, 3) == 0)
+	    {
+	      yylval.Number = tp->value;
+	      return tp->type;
+	    }
+	}
+      else if (strcmp (buff, tp->name) == 0)
+	{
+	  yylval.Number = tp->value;
+	  return tp->type;
+	}
+    }
+
+  for (tp = TimezoneTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+	yylval.Number = tp->value;
+	return tp->type;
+      }
+
+  if (strcmp (buff, "dst") == 0)
+    return tDST;
+
+  for (tp = UnitsTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+	yylval.Number = tp->value;
+	return tp->type;
+      }
+
+  /* Strip off any plural and try the units table again. */
+  i = strlen (buff) - 1;
+  if (buff[i] == 's')
+    {
+      buff[i] = '\0';
+      for (tp = UnitsTable; tp->name; tp++)
+	if (strcmp (buff, tp->name) == 0)
+	  {
+	    yylval.Number = tp->value;
+	    return tp->type;
+	  }
+      buff[i] = 's';		/* Put back for "this" in OtherTable. */
+    }
+
+  for (tp = OtherTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+	yylval.Number = tp->value;
+	return tp->type;
+      }
+
+  /* Military timezones. */
+  if (buff[1] == '\0' && ISALPHA ((unsigned char) *buff))
+    {
+      for (tp = MilitaryTable; tp->name; tp++)
+	if (strcmp (buff, tp->name) == 0)
+	  {
+	    yylval.Number = tp->value;
+	    return tp->type;
+	  }
+    }
+
+  /* Drop out any periods and try the timezone table again. */
+  for (i = 0, p = q = buff; *q; q++)
+    if (*q != '.')
+      *p++ = *q;
+    else
+      i++;
+  *p = '\0';
+  if (i)
+    for (tp = TimezoneTable; tp->name; tp++)
+      if (strcmp (buff, tp->name) == 0)
+	{
+	  yylval.Number = tp->value;
+	  return tp->type;
+	}
+
+  return tID;
+}
+
+static int
+yylex ()
+{
+  register unsigned char c;
+  register char *p;
+  char buff[20];
+  int Count;
+  int sign;
+
+  for (;;)
+    {
+      while (ISSPACE ((unsigned char) *yyInput))
+	yyInput++;
+
+      if (ISDIGIT (c = *yyInput) || c == '-' || c == '+')
+	{
+	  if (c == '-' || c == '+')
+	    {
+	      sign = c == '-' ? -1 : 1;
+	      if (!ISDIGIT (*++yyInput))
+		/* skip the '-' sign */
+		continue;
+	    }
+	  else
+	    sign = 0;
+	  for (yylval.Number = 0; ISDIGIT (c = *yyInput++);)
+	    yylval.Number = 10 * yylval.Number + c - '0';
+	  yyInput--;
+	  if (sign < 0)
+	    yylval.Number = -yylval.Number;
+	  return sign ? tSNUMBER : tUNUMBER;
+	}
+      if (ISALPHA (c))
+	{
+	  for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';)
+	    if (p < &buff[sizeof buff - 1])
+	      *p++ = c;
+	  *p = '\0';
+	  yyInput--;
+	  return LookupWord (buff);
+	}
+      if (c != '(')
+	return *yyInput++;
+      Count = 0;
+      do
+	{
+	  c = *yyInput++;
+	  if (c == '\0')
+	    return c;
+	  if (c == '(')
+	    Count++;
+	  else if (c == ')')
+	    Count--;
+	}
+      while (Count > 0);
+    }
+}
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds.  */
+static long
+difftm (struct tm *a, struct tm *b)
+{
+  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+  long days = (
+  /* difference in day of year */
+		a->tm_yday - b->tm_yday
+  /* + intervening leap days */
+		+ ((ay >> 2) - (by >> 2))
+		- (ay / 100 - by / 100)
+		+ ((ay / 100 >> 2) - (by / 100 >> 2))
+  /* + difference in years * 365 */
+		+ (long) (ay - by) * 365
+  );
+  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+		+ (a->tm_min - b->tm_min))
+	  + (a->tm_sec - b->tm_sec));
+}
+
+time_t
+get_date (const char *p, const time_t *now)
+{
+  struct tm tm, tm0, *tmp;
+  time_t Start;
+
+  yyInput = p;
+  Start = now ? *now : time ((time_t *) NULL);
+  tmp = localtime (&Start);
+  if (!tmp)
+    return -1;
+  yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
+  yyMonth = tmp->tm_mon + 1;
+  yyDay = tmp->tm_mday;
+  yyHour = tmp->tm_hour;
+  yyMinutes = tmp->tm_min;
+  yySeconds = tmp->tm_sec;
+  tm.tm_isdst = tmp->tm_isdst;
+  yyMeridian = MER24;
+  yyRelSeconds = 0;
+  yyRelMinutes = 0;
+  yyRelHour = 0;
+  yyRelDay = 0;
+  yyRelMonth = 0;
+  yyRelYear = 0;
+  yyHaveDate = 0;
+  yyHaveDay = 0;
+  yyHaveRel = 0;
+  yyHaveTime = 0;
+  yyHaveZone = 0;
+
+  if (yyparse ()
+      || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+    return -1;
+
+  tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear;
+  tm.tm_mon = yyMonth - 1 + yyRelMonth;
+  tm.tm_mday = yyDay + yyRelDay;
+  if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay))
+    {
+      tm.tm_hour = ToHour (yyHour, yyMeridian);
+      if (tm.tm_hour < 0)
+	return -1;
+      tm.tm_min = yyMinutes;
+      tm.tm_sec = yySeconds;
+    }
+  else
+    {
+      tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    }
+  tm.tm_hour += yyRelHour;
+  tm.tm_min += yyRelMinutes;
+  tm.tm_sec += yyRelSeconds;
+
+  /* Let mktime deduce tm_isdst if we have an absolute timestamp,
+     or if the relative timestamp mentions days, months, or years.  */
+  if (yyHaveDate | yyHaveDay | yyHaveTime | yyRelDay | yyRelMonth | yyRelYear)
+    tm.tm_isdst = -1;
+
+  tm0 = tm;
+
+  Start = mktime (&tm);
+
+  if (Start == (time_t) -1)
+    {
+
+      /* Guard against falsely reporting errors near the time_t boundaries
+         when parsing times in other time zones.  For example, if the min
+         time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
+         of UTC, then the min localtime value is 1970-01-01 08:00:00; if
+         we apply mktime to 1970-01-01 00:00:00 we will get an error, so
+         we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
+         zone by 24 hours to compensate.  This algorithm assumes that
+         there is no DST transition within a day of the time_t boundaries.  */
+      if (yyHaveZone)
+	{
+	  tm = tm0;
+	  if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN)
+	    {
+	      tm.tm_mday++;
+	      yyTimezone -= 24 * 60;
+	    }
+	  else
+	    {
+	      tm.tm_mday--;
+	      yyTimezone += 24 * 60;
+	    }
+	  Start = mktime (&tm);
+	}
+
+      if (Start == (time_t) -1)
+	return Start;
+    }
+
+  if (yyHaveDay && !yyHaveDate)
+    {
+      tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7
+		     + 7 * (yyDayOrdinal - (0 < yyDayOrdinal)));
+      Start = mktime (&tm);
+      if (Start == (time_t) -1)
+	return Start;
+    }
+
+  if (yyHaveZone)
+    {
+      long delta;
+      struct tm *gmt = gmtime (&Start);
+      if (!gmt)
+	return -1;
+      delta = yyTimezone * 60L + difftm (&tm, gmt);
+      if ((Start + delta < Start) != (delta < 0))
+	return -1;		/* time_t overflow */
+      Start += delta;
+    }
+
+  return Start;
+}
+
+#if	defined (TEST)
+
+/* ARGSUSED */
+int
+main (ac, av)
+     int ac;
+     char *av[];
+{
+  char buff[MAX_BUFF_LEN + 1];
+  time_t d;
+
+  (void) printf ("Enter date, or blank line to exit.\n\t> ");
+  (void) fflush (stdout);
+
+  buff[MAX_BUFF_LEN] = 0;
+  while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
+    {
+      d = get_date (buff, (time_t *) NULL);
+      if (d == -1)
+	(void) printf ("Bad format - couldn't convert.\n");
+      else
+	(void) printf ("%s", ctime (&d));
+      (void) printf ("\t> ");
+      (void) fflush (stdout);
+    }
+  exit (0);
+  /* NOTREACHED */
+}
+#endif /* defined (TEST) */
diff --git a/chrony_3_3/getdate.h b/chrony_3_3/getdate.h
new file mode 100644
index 0000000..a190d2d
--- /dev/null
+++ b/chrony_3_3/getdate.h
@@ -0,0 +1,28 @@
+/*  Copyright (C) 1995 Free Software Foundation, Inc.
+
+   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, 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. */
+
+/* Modified from the original to add stdlib.h and string.h */
+
+#ifndef GOT_GETDATE_H
+#define GOT_GETDATE_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+time_t get_date (const char *p, const time_t *now);
+
+#endif /* GOT_GETDATE_H */
diff --git a/chrony_3_3/getdate.y b/chrony_3_3/getdate.y
new file mode 100644
index 0000000..f87875c
--- /dev/null
+++ b/chrony_3_3/getdate.y
@@ -0,0 +1,1044 @@
+%{
+/*
+**  Originally written by Steven M. Bellovin <smb@research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
+**
+**  This code is in the public domain and has no copyright.
+*/
+
+#include "config.h"
+
+/* Since the code of getdate.y is not included in the Emacs executable
+   itself, there is no need to #define static in this file.  Even if
+   the code were included in the Emacs executable, it probably
+   wouldn't do any harm to #undef it here; this will only cause
+   problems if we try to write to a static variable, which I don't
+   think this code needs to do.  */
+#ifdef emacs
+# undef static
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if HAVE_STDLIB_H
+# include <stdlib.h> /* for `free'; used by Bison 1.27 */
+#endif
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+
+/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
+   - Its arg may be any int or unsigned int; it need not be an unsigned char.
+   - It's guaranteed to evaluate its argument exactly once.
+   - It's typically faster.
+   Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+   only '0' through '9' are digits.  Prefer ISDIGIT to ISDIGIT_LOCALE unless
+   it's important to use the locale's definition of `digit' even when the
+   host does not conform to Posix.  */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#if defined (STDC_HEADERS) || defined (USG)
+# include <string.h>
+#endif
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+   That loses on systems that don't provide the function, so we have
+   to redefine it here.  */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+# define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+   as well as gratuitiously global symbol names, so we can have multiple
+   yacc generated parsers in the same program.  Note that these are only
+   the variables produced by yacc.  If other parser generators (bison,
+   byacc, etc) produce additional global names that conflict at link time,
+   then those parser generators need to be fixed instead of adding those
+   names to this list. */
+
+#define yymaxdepth gd_maxdepth
+#define yyparse gd_parse
+#define yylex   gd_lex
+#define yyerror gd_error
+#define yylval  gd_lval
+#define yychar  gd_char
+#define yydebug gd_debug
+#define yypact  gd_pact
+#define yyr1    gd_r1
+#define yyr2    gd_r2
+#define yydef   gd_def
+#define yychk   gd_chk
+#define yypgo   gd_pgo
+#define yyact   gd_act
+#define yyexca  gd_exca
+#define yyerrflag gd_errflag
+#define yynerrs gd_nerrs
+#define yyps    gd_ps
+#define yypv    gd_pv
+#define yys     gd_s
+#define yy_yys  gd_yys
+#define yystate gd_state
+#define yytmp   gd_tmp
+#define yyv     gd_v
+#define yy_yyv  gd_yyv
+#define yyval   gd_val
+#define yylloc  gd_lloc
+#define yyreds  gd_reds          /* With YYDEBUG defined */
+#define yytoks  gd_toks          /* With YYDEBUG defined */
+#define yylhs   gd_yylhs
+#define yylen   gd_yylen
+#define yydefred gd_yydefred
+#define yydgoto gd_yydgoto
+#define yysindex gd_yysindex
+#define yyrindex gd_yyrindex
+#define yygindex gd_yygindex
+#define yytable  gd_yytable
+#define yycheck  gd_yycheck
+
+static int yylex (void);
+static int yyerror (char *s);
+
+#define EPOCH		1970
+#define HOUR(x)		((x) * 60)
+
+#define MAX_BUFF_LEN    128   /* size of buffer to read the date into */
+
+/*
+**  An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+    const char	*name;
+    int		type;
+    int		value;
+} TABLE;
+
+
+/*
+**  Meridian:  am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+    MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+**  Global variables.  We could get rid of most of these by using a good
+**  union as the yacc stack.  (This routine was originally written before
+**  yacc had the %union construct.)  Maybe someday; right now we only use
+**  the %union very rarely.
+*/
+static const char	*yyInput;
+static int	yyDayOrdinal;
+static int	yyDayNumber;
+static int	yyHaveDate;
+static int	yyHaveDay;
+static int	yyHaveRel;
+static int	yyHaveTime;
+static int	yyHaveZone;
+static int	yyTimezone;
+static int	yyDay;
+static int	yyHour;
+static int	yyMinutes;
+static int	yyMonth;
+static int	yySeconds;
+static int	yyYear;
+static MERIDIAN	yyMeridian;
+static int	yyRelDay;
+static int	yyRelHour;
+static int	yyRelMinutes;
+static int	yyRelMonth;
+static int	yyRelSeconds;
+static int	yyRelYear;
+
+%}
+
+/* This grammar has 13 shift/reduce conflicts. */
+%expect 13
+
+%union {
+    int			Number;
+    enum _MERIDIAN	Meridian;
+}
+
+%token	tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID
+%token	tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token	tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
+
+%type	<Number>	tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tMINUTE_UNIT
+%type	<Number>	tMONTH tMONTH_UNIT
+%type	<Number>	tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
+%type	<Meridian>	tMERIDIAN o_merid
+
+%%
+
+spec	: /* NULL */
+	| spec item
+	;
+
+item	: time {
+	    yyHaveTime++;
+	}
+	| zone {
+	    yyHaveZone++;
+	}
+	| date {
+	    yyHaveDate++;
+	}
+	| day {
+	    yyHaveDay++;
+	}
+	| rel {
+	    yyHaveRel++;
+	}
+	| number
+	;
+
+time	: tUNUMBER tMERIDIAN {
+	    yyHour = $1;
+	    yyMinutes = 0;
+	    yySeconds = 0;
+	    yyMeridian = $2;
+	}
+	| tUNUMBER ':' tUNUMBER o_merid {
+	    yyHour = $1;
+	    yyMinutes = $3;
+	    yySeconds = 0;
+	    yyMeridian = $4;
+	}
+	| tUNUMBER ':' tUNUMBER tSNUMBER {
+	    yyHour = $1;
+	    yyMinutes = $3;
+	    yyMeridian = MER24;
+	    yyHaveZone++;
+	    yyTimezone = ($4 < 0
+			  ? -$4 % 100 + (-$4 / 100) * 60
+			  : - ($4 % 100 + ($4 / 100) * 60));
+	}
+	| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+	    yyHour = $1;
+	    yyMinutes = $3;
+	    yySeconds = $5;
+	    yyMeridian = $6;
+	}
+	| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+	    yyHour = $1;
+	    yyMinutes = $3;
+	    yySeconds = $5;
+	    yyMeridian = MER24;
+	    yyHaveZone++;
+	    yyTimezone = ($6 < 0
+			  ? -$6 % 100 + (-$6 / 100) * 60
+			  : - ($6 % 100 + ($6 / 100) * 60));
+	}
+	;
+
+zone	: tZONE {
+	    yyTimezone = $1;
+	}
+	| tDAYZONE {
+	    yyTimezone = $1 - 60;
+	}
+	|
+	  tZONE tDST {
+	    yyTimezone = $1 - 60;
+	}
+	;
+
+day	: tDAY {
+	    yyDayOrdinal = 1;
+	    yyDayNumber = $1;
+	}
+	| tDAY ',' {
+	    yyDayOrdinal = 1;
+	    yyDayNumber = $1;
+	}
+	| tUNUMBER tDAY {
+	    yyDayOrdinal = $1;
+	    yyDayNumber = $2;
+	}
+	;
+
+date	: tUNUMBER '/' tUNUMBER {
+	    yyMonth = $1;
+	    yyDay = $3;
+	}
+	| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+	  /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
+	     The goal in recognizing YYYY/MM/DD is solely to support legacy
+	     machine-generated dates like those in an RCS log listing.  If
+	     you want portability, use the ISO 8601 format.  */
+	  if ($1 >= 1000)
+	    {
+	      yyYear = $1;
+	      yyMonth = $3;
+	      yyDay = $5;
+	    }
+	  else
+	    {
+	      yyMonth = $1;
+	      yyDay = $3;
+	      yyYear = $5;
+	    }
+	}
+	| tUNUMBER tSNUMBER tSNUMBER {
+	    /* ISO 8601 format.  yyyy-mm-dd.  */
+	    yyYear = $1;
+	    yyMonth = -$2;
+	    yyDay = -$3;
+	}
+	| tUNUMBER tMONTH tSNUMBER {
+	    /* e.g. 17-JUN-1992.  */
+	    yyDay = $1;
+	    yyMonth = $2;
+	    yyYear = -$3;
+	}
+	| tMONTH tUNUMBER {
+	    yyMonth = $1;
+	    yyDay = $2;
+	}
+	| tMONTH tUNUMBER ',' tUNUMBER {
+	    yyMonth = $1;
+	    yyDay = $2;
+	    yyYear = $4;
+	}
+	| tUNUMBER tMONTH {
+	    yyMonth = $2;
+	    yyDay = $1;
+	}
+	| tUNUMBER tMONTH tUNUMBER {
+	    yyMonth = $2;
+	    yyDay = $1;
+	    yyYear = $3;
+	}
+	;
+
+rel	: relunit tAGO {
+	    yyRelSeconds = -yyRelSeconds;
+	    yyRelMinutes = -yyRelMinutes;
+	    yyRelHour = -yyRelHour;
+	    yyRelDay = -yyRelDay;
+	    yyRelMonth = -yyRelMonth;
+	    yyRelYear = -yyRelYear;
+	}
+	| relunit
+	;
+
+relunit	: tUNUMBER tYEAR_UNIT {
+	    yyRelYear += $1 * $2;
+	}
+	| tSNUMBER tYEAR_UNIT {
+	    yyRelYear += $1 * $2;
+	}
+	| tYEAR_UNIT {
+	    yyRelYear += $1;
+	}
+	| tUNUMBER tMONTH_UNIT {
+	    yyRelMonth += $1 * $2;
+	}
+	| tSNUMBER tMONTH_UNIT {
+	    yyRelMonth += $1 * $2;
+	}
+	| tMONTH_UNIT {
+	    yyRelMonth += $1;
+	}
+	| tUNUMBER tDAY_UNIT {
+	    yyRelDay += $1 * $2;
+	}
+	| tSNUMBER tDAY_UNIT {
+	    yyRelDay += $1 * $2;
+	}
+	| tDAY_UNIT {
+	    yyRelDay += $1;
+	}
+	| tUNUMBER tHOUR_UNIT {
+	    yyRelHour += $1 * $2;
+	}
+	| tSNUMBER tHOUR_UNIT {
+	    yyRelHour += $1 * $2;
+	}
+	| tHOUR_UNIT {
+	    yyRelHour += $1;
+	}
+	| tUNUMBER tMINUTE_UNIT {
+	    yyRelMinutes += $1 * $2;
+	}
+	| tSNUMBER tMINUTE_UNIT {
+	    yyRelMinutes += $1 * $2;
+	}
+	| tMINUTE_UNIT {
+	    yyRelMinutes += $1;
+	}
+	| tUNUMBER tSEC_UNIT {
+	    yyRelSeconds += $1 * $2;
+	}
+	| tSNUMBER tSEC_UNIT {
+	    yyRelSeconds += $1 * $2;
+	}
+	| tSEC_UNIT {
+	    yyRelSeconds += $1;
+	}
+	;
+
+number	: tUNUMBER
+          {
+	    if (yyHaveTime && yyHaveDate && !yyHaveRel)
+	      yyYear = $1;
+	    else
+	      {
+		if ($1>10000)
+		  {
+		    yyHaveDate++;
+		    yyDay= ($1)%100;
+		    yyMonth= ($1/100)%100;
+		    yyYear = $1/10000;
+		  }
+		else
+		  {
+		    yyHaveTime++;
+		    if ($1 < 100)
+		      {
+			yyHour = $1;
+			yyMinutes = 0;
+		      }
+		    else
+		      {
+		    	yyHour = $1 / 100;
+		    	yyMinutes = $1 % 100;
+		      }
+		    yySeconds = 0;
+		    yyMeridian = MER24;
+		  }
+	      }
+	  }
+	;
+
+o_merid	: /* NULL */
+	  {
+	    $$ = MER24;
+	  }
+	| tMERIDIAN
+	  {
+	    $$ = $1;
+	  }
+	;
+
+%%
+
+/* Include this file down here because bison inserts code above which
+   may define-away `const'.  We want the prototype for get_date to have
+   the same signature as the function definition does. */
+#include "getdate.h"
+
+extern struct tm	*gmtime ();
+extern struct tm	*localtime ();
+extern time_t		mktime ();
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+    { "january",	tMONTH,  1 },
+    { "february",	tMONTH,  2 },
+    { "march",		tMONTH,  3 },
+    { "april",		tMONTH,  4 },
+    { "may",		tMONTH,  5 },
+    { "june",		tMONTH,  6 },
+    { "july",		tMONTH,  7 },
+    { "august",		tMONTH,  8 },
+    { "september",	tMONTH,  9 },
+    { "sept",		tMONTH,  9 },
+    { "october",	tMONTH, 10 },
+    { "november",	tMONTH, 11 },
+    { "december",	tMONTH, 12 },
+    { "sunday",		tDAY, 0 },
+    { "monday",		tDAY, 1 },
+    { "tuesday",	tDAY, 2 },
+    { "tues",		tDAY, 2 },
+    { "wednesday",	tDAY, 3 },
+    { "wednes",		tDAY, 3 },
+    { "thursday",	tDAY, 4 },
+    { "thur",		tDAY, 4 },
+    { "thurs",		tDAY, 4 },
+    { "friday",		tDAY, 5 },
+    { "saturday",	tDAY, 6 },
+    { NULL, 0, 0 }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+    { "year",		tYEAR_UNIT,	1 },
+    { "month",		tMONTH_UNIT,	1 },
+    { "fortnight",	tDAY_UNIT,	14 },
+    { "week",		tDAY_UNIT,	7 },
+    { "day",		tDAY_UNIT,	1 },
+    { "hour",		tHOUR_UNIT,	1 },
+    { "minute",		tMINUTE_UNIT,	1 },
+    { "min",		tMINUTE_UNIT,	1 },
+    { "second",		tSEC_UNIT,	1 },
+    { "sec",		tSEC_UNIT,	1 },
+    { NULL, 0, 0 }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+    { "tomorrow",	tMINUTE_UNIT,	1 * 24 * 60 },
+    { "yesterday",	tMINUTE_UNIT,	-1 * 24 * 60 },
+    { "today",		tMINUTE_UNIT,	0 },
+    { "now",		tMINUTE_UNIT,	0 },
+    { "last",		tUNUMBER,	-1 },
+    { "this",		tMINUTE_UNIT,	0 },
+    { "next",		tUNUMBER,	1 },
+    { "first",		tUNUMBER,	1 },
+/*  { "second",		tUNUMBER,	2 }, */
+    { "third",		tUNUMBER,	3 },
+    { "fourth",		tUNUMBER,	4 },
+    { "fifth",		tUNUMBER,	5 },
+    { "sixth",		tUNUMBER,	6 },
+    { "seventh",	tUNUMBER,	7 },
+    { "eighth",		tUNUMBER,	8 },
+    { "ninth",		tUNUMBER,	9 },
+    { "tenth",		tUNUMBER,	10 },
+    { "eleventh",	tUNUMBER,	11 },
+    { "twelfth",	tUNUMBER,	12 },
+    { "ago",		tAGO,	1 },
+    { NULL, 0, 0 }
+};
+
+/* The timezone table. */
+static TABLE const TimezoneTable[] = {
+    { "gmt",	tZONE,     HOUR ( 0) },	/* Greenwich Mean */
+    { "ut",	tZONE,     HOUR ( 0) },	/* Universal (Coordinated) */
+    { "utc",	tZONE,     HOUR ( 0) },
+    { "wet",	tZONE,     HOUR ( 0) },	/* Western European */
+    { "bst",	tDAYZONE,  HOUR ( 0) },	/* British Summer */
+    { "wat",	tZONE,     HOUR ( 1) },	/* West Africa */
+    { "at",	tZONE,     HOUR ( 2) },	/* Azores */
+#if	0
+    /* For completeness.  BST is also British Summer, and GST is
+     * also Guam Standard. */
+    { "bst",	tZONE,     HOUR ( 3) },	/* Brazil Standard */
+    { "gst",	tZONE,     HOUR ( 3) },	/* Greenland Standard */
+#endif
+#if 0
+    { "nft",	tZONE,     HOUR (3.5) },	/* Newfoundland */
+    { "nst",	tZONE,     HOUR (3.5) },	/* Newfoundland Standard */
+    { "ndt",	tDAYZONE,  HOUR (3.5) },	/* Newfoundland Daylight */
+#endif
+    { "ast",	tZONE,     HOUR ( 4) },	/* Atlantic Standard */
+    { "adt",	tDAYZONE,  HOUR ( 4) },	/* Atlantic Daylight */
+    { "est",	tZONE,     HOUR ( 5) },	/* Eastern Standard */
+    { "edt",	tDAYZONE,  HOUR ( 5) },	/* Eastern Daylight */
+    { "cst",	tZONE,     HOUR ( 6) },	/* Central Standard */
+    { "cdt",	tDAYZONE,  HOUR ( 6) },	/* Central Daylight */
+    { "mst",	tZONE,     HOUR ( 7) },	/* Mountain Standard */
+    { "mdt",	tDAYZONE,  HOUR ( 7) },	/* Mountain Daylight */
+    { "pst",	tZONE,     HOUR ( 8) },	/* Pacific Standard */
+    { "pdt",	tDAYZONE,  HOUR ( 8) },	/* Pacific Daylight */
+    { "yst",	tZONE,     HOUR ( 9) },	/* Yukon Standard */
+    { "ydt",	tDAYZONE,  HOUR ( 9) },	/* Yukon Daylight */
+    { "hst",	tZONE,     HOUR (10) },	/* Hawaii Standard */
+    { "hdt",	tDAYZONE,  HOUR (10) },	/* Hawaii Daylight */
+    { "cat",	tZONE,     HOUR (10) },	/* Central Alaska */
+    { "ahst",	tZONE,     HOUR (10) },	/* Alaska-Hawaii Standard */
+    { "nt",	tZONE,     HOUR (11) },	/* Nome */
+    { "idlw",	tZONE,     HOUR (12) },	/* International Date Line West */
+    { "cet",	tZONE,     -HOUR (1) },	/* Central European */
+    { "met",	tZONE,     -HOUR (1) },	/* Middle European */
+    { "mewt",	tZONE,     -HOUR (1) },	/* Middle European Winter */
+    { "mest",	tDAYZONE,  -HOUR (1) },	/* Middle European Summer */
+    { "mesz",	tDAYZONE,  -HOUR (1) },	/* Middle European Summer */
+    { "swt",	tZONE,     -HOUR (1) },	/* Swedish Winter */
+    { "sst",	tDAYZONE,  -HOUR (1) },	/* Swedish Summer */
+    { "fwt",	tZONE,     -HOUR (1) },	/* French Winter */
+    { "fst",	tDAYZONE,  -HOUR (1) },	/* French Summer */
+    { "eet",	tZONE,     -HOUR (2) },	/* Eastern Europe, USSR Zone 1 */
+    { "bt",	tZONE,     -HOUR (3) },	/* Baghdad, USSR Zone 2 */
+#if 0
+    { "it",	tZONE,     -HOUR (3.5) },/* Iran */
+#endif
+    { "zp4",	tZONE,     -HOUR (4) },	/* USSR Zone 3 */
+    { "zp5",	tZONE,     -HOUR (5) },	/* USSR Zone 4 */
+#if 0
+    { "ist",	tZONE,     -HOUR (5.5) },/* Indian Standard */
+#endif
+    { "zp6",	tZONE,     -HOUR (6) },	/* USSR Zone 5 */
+#if	0
+    /* For completeness.  NST is also Newfoundland Standard, and SST is
+     * also Swedish Summer. */
+    { "nst",	tZONE,     -HOUR (6.5) },/* North Sumatra */
+    { "sst",	tZONE,     -HOUR (7) },	/* South Sumatra, USSR Zone 6 */
+#endif	/* 0 */
+    { "wast",	tZONE,     -HOUR (7) },	/* West Australian Standard */
+    { "wadt",	tDAYZONE,  -HOUR (7) },	/* West Australian Daylight */
+#if 0
+    { "jt",	tZONE,     -HOUR (7.5) },/* Java (3pm in Cronusland!) */
+#endif
+    { "cct",	tZONE,     -HOUR (8) },	/* China Coast, USSR Zone 7 */
+    { "jst",	tZONE,     -HOUR (9) },	/* Japan Standard, USSR Zone 8 */
+#if 0
+    { "cast",	tZONE,     -HOUR (9.5) },/* Central Australian Standard */
+    { "cadt",	tDAYZONE,  -HOUR (9.5) },/* Central Australian Daylight */
+#endif
+    { "east",	tZONE,     -HOUR (10) },	/* Eastern Australian Standard */
+    { "eadt",	tDAYZONE,  -HOUR (10) },	/* Eastern Australian Daylight */
+    { "gst",	tZONE,     -HOUR (10) },	/* Guam Standard, USSR Zone 9 */
+    { "nzt",	tZONE,     -HOUR (12) },	/* New Zealand */
+    { "nzst",	tZONE,     -HOUR (12) },	/* New Zealand Standard */
+    { "nzdt",	tDAYZONE,  -HOUR (12) },	/* New Zealand Daylight */
+    { "idle",	tZONE,     -HOUR (12) },	/* International Date Line East */
+    {  NULL, 0, 0  }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+    { "a",	tZONE,	HOUR (  1) },
+    { "b",	tZONE,	HOUR (  2) },
+    { "c",	tZONE,	HOUR (  3) },
+    { "d",	tZONE,	HOUR (  4) },
+    { "e",	tZONE,	HOUR (  5) },
+    { "f",	tZONE,	HOUR (  6) },
+    { "g",	tZONE,	HOUR (  7) },
+    { "h",	tZONE,	HOUR (  8) },
+    { "i",	tZONE,	HOUR (  9) },
+    { "k",	tZONE,	HOUR ( 10) },
+    { "l",	tZONE,	HOUR ( 11) },
+    { "m",	tZONE,	HOUR ( 12) },
+    { "n",	tZONE,	HOUR (- 1) },
+    { "o",	tZONE,	HOUR (- 2) },
+    { "p",	tZONE,	HOUR (- 3) },
+    { "q",	tZONE,	HOUR (- 4) },
+    { "r",	tZONE,	HOUR (- 5) },
+    { "s",	tZONE,	HOUR (- 6) },
+    { "t",	tZONE,	HOUR (- 7) },
+    { "u",	tZONE,	HOUR (- 8) },
+    { "v",	tZONE,	HOUR (- 9) },
+    { "w",	tZONE,	HOUR (-10) },
+    { "x",	tZONE,	HOUR (-11) },
+    { "y",	tZONE,	HOUR (-12) },
+    { "z",	tZONE,	HOUR (  0) },
+    { NULL, 0, 0 }
+};
+
+
+
+
+/* ARGSUSED */
+static int
+yyerror (s)
+     char *s ATTRIBUTE_UNUSED;
+{
+  return 0;
+}
+
+static int
+ToHour (Hours, Meridian)
+     int Hours;
+     MERIDIAN Meridian;
+{
+  switch (Meridian)
+    {
+    case MER24:
+      if (Hours < 0 || Hours > 23)
+	return -1;
+      return Hours;
+    case MERam:
+      if (Hours < 1 || Hours > 12)
+	return -1;
+      if (Hours == 12)
+	Hours = 0;
+      return Hours;
+    case MERpm:
+      if (Hours < 1 || Hours > 12)
+	return -1;
+      if (Hours == 12)
+	Hours = 0;
+      return Hours + 12;
+    default:
+      abort ();
+    }
+  /* NOTREACHED */
+}
+
+static int
+ToYear (Year)
+     int Year;
+{
+  if (Year < 0)
+    Year = -Year;
+
+  /* XPG4 suggests that years 00-68 map to 2000-2068, and
+     years 69-99 map to 1969-1999.  */
+  if (Year < 69)
+    Year += 2000;
+  else if (Year < 100)
+    Year += 1900;
+
+  return Year;
+}
+
+static int
+LookupWord (buff)
+     char *buff;
+{
+  register char *p;
+  register char *q;
+  register const TABLE *tp;
+  int i;
+  int abbrev;
+
+  /* Make it lowercase. */
+  for (p = buff; *p; p++)
+    if (ISUPPER ((unsigned char) *p))
+      *p = tolower ((unsigned char) *p);
+
+  if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
+    {
+      yylval.Meridian = MERam;
+      return tMERIDIAN;
+    }
+  if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0)
+    {
+      yylval.Meridian = MERpm;
+      return tMERIDIAN;
+    }
+
+  /* See if we have an abbreviation for a month. */
+  if (strlen (buff) == 3)
+    abbrev = 1;
+  else if (strlen (buff) == 4 && buff[3] == '.')
+    {
+      abbrev = 1;
+      buff[3] = '\0';
+    }
+  else
+    abbrev = 0;
+
+  for (tp = MonthDayTable; tp->name; tp++)
+    {
+      if (abbrev)
+	{
+	  if (strncmp (buff, tp->name, 3) == 0)
+	    {
+	      yylval.Number = tp->value;
+	      return tp->type;
+	    }
+	}
+      else if (strcmp (buff, tp->name) == 0)
+	{
+	  yylval.Number = tp->value;
+	  return tp->type;
+	}
+    }
+
+  for (tp = TimezoneTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+	yylval.Number = tp->value;
+	return tp->type;
+      }
+
+  if (strcmp (buff, "dst") == 0)
+    return tDST;
+
+  for (tp = UnitsTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+	yylval.Number = tp->value;
+	return tp->type;
+      }
+
+  /* Strip off any plural and try the units table again. */
+  i = strlen (buff) - 1;
+  if (buff[i] == 's')
+    {
+      buff[i] = '\0';
+      for (tp = UnitsTable; tp->name; tp++)
+	if (strcmp (buff, tp->name) == 0)
+	  {
+	    yylval.Number = tp->value;
+	    return tp->type;
+	  }
+      buff[i] = 's';		/* Put back for "this" in OtherTable. */
+    }
+
+  for (tp = OtherTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+	yylval.Number = tp->value;
+	return tp->type;
+      }
+
+  /* Military timezones. */
+  if (buff[1] == '\0' && ISALPHA ((unsigned char) *buff))
+    {
+      for (tp = MilitaryTable; tp->name; tp++)
+	if (strcmp (buff, tp->name) == 0)
+	  {
+	    yylval.Number = tp->value;
+	    return tp->type;
+	  }
+    }
+
+  /* Drop out any periods and try the timezone table again. */
+  for (i = 0, p = q = buff; *q; q++)
+    if (*q != '.')
+      *p++ = *q;
+    else
+      i++;
+  *p = '\0';
+  if (i)
+    for (tp = TimezoneTable; tp->name; tp++)
+      if (strcmp (buff, tp->name) == 0)
+	{
+	  yylval.Number = tp->value;
+	  return tp->type;
+	}
+
+  return tID;
+}
+
+static int
+yylex ()
+{
+  register unsigned char c;
+  register char *p;
+  char buff[20];
+  int Count;
+  int sign;
+
+  for (;;)
+    {
+      while (ISSPACE ((unsigned char) *yyInput))
+	yyInput++;
+
+      if (ISDIGIT (c = *yyInput) || c == '-' || c == '+')
+	{
+	  if (c == '-' || c == '+')
+	    {
+	      sign = c == '-' ? -1 : 1;
+	      if (!ISDIGIT (*++yyInput))
+		/* skip the '-' sign */
+		continue;
+	    }
+	  else
+	    sign = 0;
+	  for (yylval.Number = 0; ISDIGIT (c = *yyInput++);)
+	    yylval.Number = 10 * yylval.Number + c - '0';
+	  yyInput--;
+	  if (sign < 0)
+	    yylval.Number = -yylval.Number;
+	  return sign ? tSNUMBER : tUNUMBER;
+	}
+      if (ISALPHA (c))
+	{
+	  for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';)
+	    if (p < &buff[sizeof buff - 1])
+	      *p++ = c;
+	  *p = '\0';
+	  yyInput--;
+	  return LookupWord (buff);
+	}
+      if (c != '(')
+	return *yyInput++;
+      Count = 0;
+      do
+	{
+	  c = *yyInput++;
+	  if (c == '\0')
+	    return c;
+	  if (c == '(')
+	    Count++;
+	  else if (c == ')')
+	    Count--;
+	}
+      while (Count > 0);
+    }
+}
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds.  */
+static long
+difftm (struct tm *a, struct tm *b)
+{
+  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+  long days = (
+  /* difference in day of year */
+		a->tm_yday - b->tm_yday
+  /* + intervening leap days */
+		+ ((ay >> 2) - (by >> 2))
+		- (ay / 100 - by / 100)
+		+ ((ay / 100 >> 2) - (by / 100 >> 2))
+  /* + difference in years * 365 */
+		+ (long) (ay - by) * 365
+  );
+  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+		+ (a->tm_min - b->tm_min))
+	  + (a->tm_sec - b->tm_sec));
+}
+
+time_t
+get_date (const char *p, const time_t *now)
+{
+  struct tm tm, tm0, *tmp;
+  time_t Start;
+
+  yyInput = p;
+  Start = now ? *now : time ((time_t *) NULL);
+  tmp = localtime (&Start);
+  if (!tmp)
+    return -1;
+  yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
+  yyMonth = tmp->tm_mon + 1;
+  yyDay = tmp->tm_mday;
+  yyHour = tmp->tm_hour;
+  yyMinutes = tmp->tm_min;
+  yySeconds = tmp->tm_sec;
+  tm.tm_isdst = tmp->tm_isdst;
+  yyMeridian = MER24;
+  yyRelSeconds = 0;
+  yyRelMinutes = 0;
+  yyRelHour = 0;
+  yyRelDay = 0;
+  yyRelMonth = 0;
+  yyRelYear = 0;
+  yyHaveDate = 0;
+  yyHaveDay = 0;
+  yyHaveRel = 0;
+  yyHaveTime = 0;
+  yyHaveZone = 0;
+
+  if (yyparse ()
+      || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+    return -1;
+
+  tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear;
+  tm.tm_mon = yyMonth - 1 + yyRelMonth;
+  tm.tm_mday = yyDay + yyRelDay;
+  if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay))
+    {
+      tm.tm_hour = ToHour (yyHour, yyMeridian);
+      if (tm.tm_hour < 0)
+	return -1;
+      tm.tm_min = yyMinutes;
+      tm.tm_sec = yySeconds;
+    }
+  else
+    {
+      tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    }
+  tm.tm_hour += yyRelHour;
+  tm.tm_min += yyRelMinutes;
+  tm.tm_sec += yyRelSeconds;
+
+  /* Let mktime deduce tm_isdst if we have an absolute timestamp,
+     or if the relative timestamp mentions days, months, or years.  */
+  if (yyHaveDate | yyHaveDay | yyHaveTime | yyRelDay | yyRelMonth | yyRelYear)
+    tm.tm_isdst = -1;
+
+  tm0 = tm;
+
+  Start = mktime (&tm);
+
+  if (Start == (time_t) -1)
+    {
+
+      /* Guard against falsely reporting errors near the time_t boundaries
+         when parsing times in other time zones.  For example, if the min
+         time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
+         of UTC, then the min localtime value is 1970-01-01 08:00:00; if
+         we apply mktime to 1970-01-01 00:00:00 we will get an error, so
+         we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
+         zone by 24 hours to compensate.  This algorithm assumes that
+         there is no DST transition within a day of the time_t boundaries.  */
+      if (yyHaveZone)
+	{
+	  tm = tm0;
+	  if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN)
+	    {
+	      tm.tm_mday++;
+	      yyTimezone -= 24 * 60;
+	    }
+	  else
+	    {
+	      tm.tm_mday--;
+	      yyTimezone += 24 * 60;
+	    }
+	  Start = mktime (&tm);
+	}
+
+      if (Start == (time_t) -1)
+	return Start;
+    }
+
+  if (yyHaveDay && !yyHaveDate)
+    {
+      tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7
+		     + 7 * (yyDayOrdinal - (0 < yyDayOrdinal)));
+      Start = mktime (&tm);
+      if (Start == (time_t) -1)
+	return Start;
+    }
+
+  if (yyHaveZone)
+    {
+      long delta;
+      struct tm *gmt = gmtime (&Start);
+      if (!gmt)
+	return -1;
+      delta = yyTimezone * 60L + difftm (&tm, gmt);
+      if ((Start + delta < Start) != (delta < 0))
+	return -1;		/* time_t overflow */
+      Start += delta;
+    }
+
+  return Start;
+}
+
+#if	defined (TEST)
+
+/* ARGSUSED */
+int
+main (ac, av)
+     int ac;
+     char *av[];
+{
+  char buff[MAX_BUFF_LEN + 1];
+  time_t d;
+
+  (void) printf ("Enter date, or blank line to exit.\n\t> ");
+  (void) fflush (stdout);
+
+  buff[MAX_BUFF_LEN] = 0;
+  while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
+    {
+      d = get_date (buff, (time_t *) NULL);
+      if (d == -1)
+	(void) printf ("Bad format - couldn't convert.\n");
+      else
+	(void) printf ("%s", ctime (&d));
+      (void) printf ("\t> ");
+      (void) fflush (stdout);
+    }
+  exit (0);
+  /* NOTREACHED */
+}
+#endif /* defined (TEST) */
diff --git a/chrony_3_3/hash.h b/chrony_3_3/hash.h
new file mode 100644
index 0000000..185da66
--- /dev/null
+++ b/chrony_3_3/hash.h
@@ -0,0 +1,43 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2012
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Header file for crypto hashing.
+
+  */
+
+#ifndef GOT_HASH_H
+#define GOT_HASH_H
+
+/* length of hash values produced by SHA512 */
+#define MAX_HASH_LENGTH 64
+
+extern int HSH_GetHashId(const char *name);
+
+extern unsigned int HSH_Hash(int id,
+    const unsigned char *in1, unsigned int in1_len,
+    const unsigned char *in2, unsigned int in2_len,
+    unsigned char *out, unsigned int out_len);
+
+extern void HSH_Finalise(void);
+
+#endif
diff --git a/chrony_3_3/hash_intmd5.c b/chrony_3_3/hash_intmd5.c
new file mode 100644
index 0000000..64e0b9c
--- /dev/null
+++ b/chrony_3_3/hash_intmd5.c
@@ -0,0 +1,69 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2012
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Routines implementing crypto hashing using internal MD5 implementation.
+
+  */
+
+#include "config.h"
+#include "sysincl.h"
+#include "hash.h"
+#include "memory.h"
+
+#include "md5.c"
+
+static MD5_CTX ctx;
+
+int
+HSH_GetHashId(const char *name)
+{
+  /* only MD5 is supported */
+  if (strcmp(name, "MD5"))
+    return -1;
+
+  return 0;
+}
+
+unsigned int
+HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
+    const unsigned char *in2, unsigned int in2_len,
+    unsigned char *out, unsigned int out_len)
+{
+  if (out_len < 16)
+    return 0;
+
+  MD5Init(&ctx);
+  MD5Update(&ctx, in1, in1_len);
+  if (in2)
+    MD5Update(&ctx, in2, in2_len);
+  MD5Final(&ctx);
+
+  memcpy(out, ctx.digest, 16);
+
+  return 16;
+}
+
+void
+HSH_Finalise(void)
+{
+}
diff --git a/chrony_3_3/hash_nettle.c b/chrony_3_3/hash_nettle.c
new file mode 100644
index 0000000..2c3501d
--- /dev/null
+++ b/chrony_3_3/hash_nettle.c
@@ -0,0 +1,120 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Routines implementing crypto hashing using the nettle library.
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include <nettle/nettle-meta.h>
+
+#include "hash.h"
+#include "memory.h"
+
+struct hash {
+  const char *name;
+  const char *int_name;
+  const struct nettle_hash *nettle_hash;
+  void *context;
+};
+
+static struct hash hashes[] = {
+  { "MD5", "md5", NULL, NULL },
+  { "RMD160", "ripemd160", NULL, NULL },
+  { "SHA1", "sha1", NULL, NULL },
+  { "SHA256", "sha256", NULL, NULL },
+  { "SHA384", "sha384", NULL, NULL },
+  { "SHA512", "sha512", NULL, NULL },
+  { "SHA3-224", "sha3_224", NULL, NULL },
+  { "SHA3-256", "sha3_256", NULL, NULL },
+  { "SHA3-384", "sha3_384", NULL, NULL },
+  { "SHA3-512", "sha3_512", NULL, NULL },
+  { NULL, NULL, NULL, NULL }
+};
+
+int
+HSH_GetHashId(const char *name)
+{
+  int id, nid;
+
+  for (id = 0; hashes[id].name; id++) {
+    if (!strcmp(name, hashes[id].name))
+      break;
+  }
+
+  if (!hashes[id].name)
+    return -1;
+
+  if (hashes[id].context)
+    return id;
+
+  for (nid = 0; nettle_hashes[nid]; nid++) {
+    if (!strcmp(hashes[id].int_name, nettle_hashes[nid]->name))
+      break;
+  }
+
+  if (!nettle_hashes[nid] || !nettle_hashes[nid]->context_size || !nettle_hashes[nid]->init)
+    return -1;
+
+  hashes[id].nettle_hash = nettle_hashes[nid];
+  hashes[id].context = Malloc(hashes[id].nettle_hash->context_size);
+
+  return id;
+}
+
+unsigned int
+HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
+         const unsigned char *in2, unsigned int in2_len,
+         unsigned char *out, unsigned int out_len)
+{
+  const struct nettle_hash *hash;
+  void *context;
+
+  hash = hashes[id].nettle_hash;
+  context = hashes[id].context;
+
+  if (out_len > hash->digest_size)
+    out_len = hash->digest_size;
+
+  hash->init(context);
+  hash->update(context, in1_len, in1);
+  if (in2)
+    hash->update(context, in2_len, in2);
+  hash->digest(context, out_len, out);
+
+  return out_len;
+}
+
+void
+HSH_Finalise(void)
+{
+  int i;
+
+  for (i = 0; hashes[i].name; i++) {
+    if (hashes[i].context)
+      Free(hashes[i].context);
+  }
+}
diff --git a/chrony_3_3/hash_nss.c b/chrony_3_3/hash_nss.c
new file mode 100644
index 0000000..eb1f050
--- /dev/null
+++ b/chrony_3_3/hash_nss.c
@@ -0,0 +1,104 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2012
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Routines implementing crypto hashing using NSSLOWHASH API of the NSS library.
+
+  */
+
+#include "config.h"
+
+#include <nss.h>
+#include <hasht.h>
+#include <nsslowhash.h>
+
+#include "hash.h"
+
+static NSSLOWInitContext *ictx;
+
+struct hash {
+  HASH_HashType type;
+  const char *name;
+  NSSLOWHASHContext *context;
+};
+
+static struct hash hashes[] = {
+  { HASH_AlgMD5, "MD5", NULL },
+  { HASH_AlgSHA1, "SHA1", NULL },
+  { HASH_AlgSHA256, "SHA256", NULL },
+  { HASH_AlgSHA384, "SHA384", NULL },
+  { HASH_AlgSHA512, "SHA512", NULL },
+  { 0, NULL, NULL }
+};
+
+int
+HSH_GetHashId(const char *name)
+{
+  int i;
+
+  for (i = 0; hashes[i].name; i++) {
+    if (!strcmp(name, hashes[i].name))
+      break;
+  }
+
+  if (!hashes[i].name)
+    return -1; /* not found */
+
+  if (!ictx && !(ictx = NSSLOW_Init()))
+    return -1; /* couldn't init NSS */
+
+  if (!hashes[i].context &&
+      !(hashes[i].context = NSSLOWHASH_NewContext(ictx, hashes[i].type)))
+    return -1; /* couldn't init hash */
+
+  return i;
+}
+
+unsigned int
+HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
+    const unsigned char *in2, unsigned int in2_len,
+    unsigned char *out, unsigned int out_len)
+{
+  unsigned int ret = 0;
+
+  NSSLOWHASH_Begin(hashes[id].context);
+  NSSLOWHASH_Update(hashes[id].context, in1, in1_len);
+  if (in2)
+    NSSLOWHASH_Update(hashes[id].context, in2, in2_len);
+  NSSLOWHASH_End(hashes[id].context, out, &ret, out_len);
+
+  return ret;
+}
+
+void
+HSH_Finalise(void)
+{
+  int i;
+
+  for (i = 0; hashes[i].name; i++) {
+    if (hashes[i].context)
+      NSSLOWHASH_Destroy(hashes[i].context);
+  }
+
+  if (ictx)
+    NSSLOW_Shutdown(ictx);
+}
diff --git a/chrony_3_3/hash_tomcrypt.c b/chrony_3_3/hash_tomcrypt.c
new file mode 100644
index 0000000..5e16233
--- /dev/null
+++ b/chrony_3_3/hash_tomcrypt.c
@@ -0,0 +1,127 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2012
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Routines implementing crypto hashing using tomcrypt library.
+
+  */
+
+#include <tomcrypt.h>
+
+#include "config.h"
+#include "hash.h"
+
+struct hash {
+  const char *name;
+  const char *int_name;
+  const struct ltc_hash_descriptor *desc;
+};
+
+static const struct hash hashes[] = {
+  { "MD5", "md5", &md5_desc },
+#ifdef LTC_RIPEMD128
+  { "RMD128", "rmd128", &rmd128_desc },
+#endif
+#ifdef LTC_RIPEMD160
+  { "RMD160", "rmd160", &rmd160_desc },
+#endif
+#ifdef LTC_RIPEMD256
+  { "RMD256", "rmd256", &rmd256_desc },
+#endif
+#ifdef LTC_RIPEMD320
+  { "RMD320", "rmd320", &rmd320_desc },
+#endif
+#ifdef LTC_SHA1
+  { "SHA1", "sha1", &sha1_desc },
+#endif
+#ifdef LTC_SHA256
+  { "SHA256", "sha256", &sha256_desc },
+#endif
+#ifdef LTC_SHA384
+  { "SHA384", "sha384", &sha384_desc },
+#endif
+#ifdef LTC_SHA512
+  { "SHA512", "sha512", &sha512_desc },
+#endif
+#ifdef LTC_SHA3
+  { "SHA3-224", "sha3-224", &sha3_224_desc },
+  { "SHA3-256", "sha3-256", &sha3_256_desc },
+  { "SHA3-384", "sha3-384", &sha3_384_desc },
+  { "SHA3-512", "sha3-512", &sha3_512_desc },
+#endif
+#ifdef LTC_TIGER
+  { "TIGER", "tiger", &tiger_desc },
+#endif
+#ifdef LTC_WHIRLPOOL
+  { "WHIRLPOOL", "whirlpool", &whirlpool_desc },
+#endif
+  { NULL, NULL, NULL }
+};
+
+int
+HSH_GetHashId(const char *name)
+{
+  int i, h;
+
+  for (i = 0; hashes[i].name; i++) {
+    if (!strcmp(name, hashes[i].name))
+      break;
+  }
+
+  if (!hashes[i].name)
+    return -1; /* not found */
+
+  h = find_hash(hashes[i].int_name);
+  if (h >= 0)
+    return h; /* already registered */
+  
+  /* register and try again */
+  register_hash(hashes[i].desc);
+
+  return find_hash(hashes[i].int_name);
+}
+
+unsigned int
+HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
+    const unsigned char *in2, unsigned int in2_len,
+    unsigned char *out, unsigned int out_len)
+{
+  unsigned long len;
+  int r;
+
+  len = out_len;
+  if (in2)
+    r = hash_memory_multi(id, out, &len,
+        in1, (unsigned long)in1_len, in2, (unsigned long)in2_len, NULL, 0);
+  else
+    r = hash_memory(id, in1, in1_len, out, &len);
+
+  if (r != CRYPT_OK)
+    return 0;
+
+  return len;
+}
+
+void
+HSH_Finalise(void)
+{
+}
diff --git a/chrony_3_3/hwclock.c b/chrony_3_3/hwclock.c
new file mode 100644
index 0000000..007d19d
--- /dev/null
+++ b/chrony_3_3/hwclock.c
@@ -0,0 +1,213 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2016-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Tracking of hardware clocks (e.g. RTC, PHC)
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "array.h"
+#include "hwclock.h"
+#include "local.h"
+#include "logging.h"
+#include "memory.h"
+#include "regress.h"
+#include "util.h"
+
+/* Maximum number of samples per clock */
+#define MAX_SAMPLES 16
+
+/* Maximum acceptable frequency offset of the clock */
+#define MAX_FREQ_OFFSET (2.0 / 3.0)
+
+struct HCL_Instance_Record {
+  /* HW and local reference timestamp */
+  struct timespec hw_ref;
+  struct timespec local_ref;
+
+  /* Samples stored as intervals (uncorrected for frequency error)
+     relative to local_ref and hw_ref */
+  double x_data[MAX_SAMPLES];
+  double y_data[MAX_SAMPLES];
+
+  /* Number of samples */
+  int n_samples;
+
+  /* Maximum error of the last sample */
+  double last_err;
+
+  /* Minimum interval between samples */
+  double min_separation;
+
+  /* Flag indicating the offset and frequency values are valid */
+  int valid_coefs;
+
+  /* Estimated offset and frequency of HW clock relative to local clock */
+  double offset;
+  double frequency;
+};
+
+/* ================================================== */
+
+static void
+handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
+            double doffset, LCL_ChangeType change_type, void *anything)
+{
+  HCL_Instance clock;
+  double delta;
+
+  clock = anything;
+
+  if (clock->n_samples)
+    UTI_AdjustTimespec(&clock->local_ref, cooked, &clock->local_ref, &delta, dfreq, doffset);
+  if (clock->valid_coefs)
+    clock->frequency /= 1.0 - dfreq;
+}
+
+/* ================================================== */
+
+HCL_Instance
+HCL_CreateInstance(double min_separation)
+{
+  HCL_Instance clock;
+
+  clock = MallocNew(struct HCL_Instance_Record);
+  clock->x_data[MAX_SAMPLES - 1] = 0.0;
+  clock->y_data[MAX_SAMPLES - 1] = 0.0;
+  clock->n_samples = 0;
+  clock->valid_coefs = 0;
+  clock->min_separation = min_separation;
+
+  LCL_AddParameterChangeHandler(handle_slew, clock);
+
+  return clock;
+}
+
+/* ================================================== */
+
+void HCL_DestroyInstance(HCL_Instance clock)
+{
+  LCL_RemoveParameterChangeHandler(handle_slew, clock);
+  Free(clock);
+}
+
+/* ================================================== */
+
+int
+HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now)
+{
+  if (!clock->n_samples ||
+      fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= clock->min_separation)
+    return 1;
+
+  return 0;
+}
+
+/* ================================================== */
+
+void
+HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
+                     struct timespec *local_ts, double err)
+{
+  double hw_delta, local_delta, local_freq, raw_freq;
+  int i, n_runs, best_start;
+
+  local_freq = 1.0 - LCL_ReadAbsoluteFrequency() / 1.0e6;
+
+  /* Shift old samples */
+  if (clock->n_samples) {
+    if (clock->n_samples >= MAX_SAMPLES)
+      clock->n_samples--;
+
+    hw_delta = UTI_DiffTimespecsToDouble(hw_ts, &clock->hw_ref);
+    local_delta = UTI_DiffTimespecsToDouble(local_ts, &clock->local_ref) / local_freq;
+
+    if (hw_delta <= 0.0 || local_delta < clock->min_separation / 2.0) {
+      clock->n_samples = 0;
+      DEBUG_LOG("HW clock reset interval=%f", local_delta);
+    }
+
+    for (i = MAX_SAMPLES - clock->n_samples; i < MAX_SAMPLES; i++) {
+      clock->y_data[i - 1] = clock->y_data[i] - hw_delta;
+      clock->x_data[i - 1] = clock->x_data[i] - local_delta;
+    }
+  }
+
+  clock->n_samples++;
+  clock->hw_ref = *hw_ts;
+  clock->local_ref = *local_ts;
+  clock->last_err = err;
+
+  /* Get new coefficients */
+  clock->valid_coefs =
+    RGR_FindBestRobustRegression(clock->x_data + MAX_SAMPLES - clock->n_samples,
+                                 clock->y_data + MAX_SAMPLES - clock->n_samples,
+                                 clock->n_samples, 1.0e-10, &clock->offset, &raw_freq,
+                                 &n_runs, &best_start);
+
+  if (!clock->valid_coefs) {
+    DEBUG_LOG("HW clock needs more samples");
+    return;
+  }
+
+  clock->frequency = raw_freq / local_freq;
+
+  /* Drop unneeded samples */
+  clock->n_samples -= best_start;
+
+  /* If the fit doesn't cross the error interval of the last sample,
+     or the frequency is not sane, drop all samples and start again */
+  if (fabs(clock->offset) > err ||
+      fabs(clock->frequency - 1.0) > MAX_FREQ_OFFSET) {
+    DEBUG_LOG("HW clock reset");
+    clock->n_samples = 0;
+    clock->valid_coefs = 0;
+  }
+
+  DEBUG_LOG("HW clock samples=%d offset=%e freq=%e raw_freq=%e err=%e ref_diff=%e",
+            clock->n_samples, clock->offset, clock->frequency - 1.0, raw_freq - 1.0, err,
+            UTI_DiffTimespecsToDouble(&clock->hw_ref, &clock->local_ref));
+}
+
+/* ================================================== */
+
+int
+HCL_CookTime(HCL_Instance clock, struct timespec *raw, struct timespec *cooked, double *err)
+{
+  double offset, elapsed;
+
+  if (!clock->valid_coefs)
+    return 0;
+
+  elapsed = UTI_DiffTimespecsToDouble(raw, &clock->hw_ref);
+  offset = elapsed / clock->frequency - clock->offset;
+  UTI_AddDoubleToTimespec(&clock->local_ref, offset, cooked);
+
+  /* Fow now, just return the error of the last sample */
+  if (err)
+    *err = clock->last_err;
+
+  return 1;
+}
diff --git a/chrony_3_3/hwclock.h b/chrony_3_3/hwclock.h
new file mode 100644
index 0000000..f80d09a
--- /dev/null
+++ b/chrony_3_3/hwclock.h
@@ -0,0 +1,48 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Header for tracking of hardware clocks */
+
+#ifndef GOT_HWCLOCK_H
+#define GOT_HWCLOCK_H
+
+typedef struct HCL_Instance_Record *HCL_Instance;
+
+/* Create a new HW clock instance */
+extern HCL_Instance HCL_CreateInstance(double min_separation);
+
+/* Destroy a HW clock instance */
+extern void HCL_DestroyInstance(HCL_Instance clock);
+
+/* Check if a new sample should be accumulated at this time */
+extern int HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now);
+
+/* Accumulate a new sample */
+extern void HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
+                                 struct timespec *local_ts, double err);
+
+/* Convert raw hardware time to cooked local time */
+extern int HCL_CookTime(HCL_Instance clock, struct timespec *raw, struct timespec *cooked,
+                        double *err);
+
+#endif
diff --git a/chrony_3_3/keys.c b/chrony_3_3/keys.c
new file mode 100644
index 0000000..74b57c4
--- /dev/null
+++ b/chrony_3_3/keys.c
@@ -0,0 +1,411 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2012-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 managing keys used for authenticating NTP packets and commands
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "array.h"
+#include "keys.h"
+#include "cmdparse.h"
+#include "conf.h"
+#include "memory.h"
+#include "util.h"
+#include "local.h"
+#include "logging.h"
+
+/* Consider 80 bits as the absolute minimum for a secure key */
+#define MIN_SECURE_KEY_LENGTH 10
+
+typedef struct {
+  uint32_t id;
+  char *val;
+  int len;
+  int hash_id;
+  int auth_delay;
+} Key;
+
+static ARR_Instance keys;
+
+static int cache_valid;
+static uint32_t cache_key_id;
+static int cache_key_pos;
+
+/* ================================================== */
+
+static void
+free_keys(void)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARR_GetSize(keys); i++)
+    Free(((Key *)ARR_GetElement(keys, i))->val);
+
+  ARR_SetSize(keys, 0);
+  cache_valid = 0;
+}
+
+/* ================================================== */
+
+void
+KEY_Initialise(void)
+{
+  keys = ARR_CreateInstance(sizeof (Key));
+  cache_valid = 0;
+  KEY_Reload();
+}
+
+/* ================================================== */
+
+void
+KEY_Finalise(void)
+{
+  free_keys();
+  ARR_DestroyInstance(keys);
+}
+
+/* ================================================== */
+
+static Key *
+get_key(unsigned int index)
+{
+  return ((Key *)ARR_GetElements(keys)) + index;
+}
+
+/* ================================================== */
+
+static int
+determine_hash_delay(uint32_t key_id)
+{
+  NTP_Packet pkt;
+  struct timespec before, after;
+  double diff, min_diff;
+  int i, nsecs;
+
+  for (i = 0; i < 10; i++) {
+    LCL_ReadRawTime(&before);
+    KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_LENGTH,
+        (unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
+    LCL_ReadRawTime(&after);
+
+    diff = UTI_DiffTimespecsToDouble(&after, &before);
+
+    if (i == 0 || min_diff > diff)
+      min_diff = diff;
+  }
+
+  /* Add on a bit extra to allow for copying, conversions etc */
+  nsecs = 1.0625e9 * min_diff;
+
+  DEBUG_LOG("authentication delay for key %"PRIu32": %d nsecs", key_id, nsecs);
+
+  return nsecs;
+}
+
+/* ================================================== */
+/* Decode password encoded in ASCII or HEX */
+
+static int
+decode_password(char *key)
+{
+  int i, j, len = strlen(key);
+  char buf[3], *p;
+
+  if (!strncmp(key, "ASCII:", 6)) {
+    memmove(key, key + 6, len - 6);
+    return len - 6;
+  } else if (!strncmp(key, "HEX:", 4)) {
+    if ((len - 4) % 2)
+      return 0;
+
+    for (i = 0, j = 4; j + 1 < len; i++, j += 2) {
+      buf[0] = key[j], buf[1] = key[j + 1], buf[2] = '\0';
+      key[i] = strtol(buf, &p, 16);
+
+      if (p != buf + 2)
+        return 0;
+    }
+
+    return i;
+  } else {
+    /* assume ASCII */
+    return len;
+  }
+}
+
+/* ================================================== */
+
+/* Compare two keys */
+
+static int
+compare_keys_by_id(const void *a, const void *b)
+{
+  const Key *c = (const Key *) a;
+  const Key *d = (const Key *) b;
+
+  if (c->id < d->id) {
+    return -1;
+  } else if (c->id > d->id) {
+    return +1;
+  } else {
+    return 0;
+  }
+
+}
+
+/* ================================================== */
+
+void
+KEY_Reload(void)
+{
+  unsigned int i, line_number;
+  FILE *in;
+  uint32_t key_id;
+  char line[2048], *keyval, *key_file;
+  const char *hashname;
+  Key key;
+
+  free_keys();
+
+  key_file = CNF_GetKeysFile();
+  line_number = 0;
+
+  if (!key_file)
+    return;
+
+  in = fopen(key_file, "r");
+  if (!in) {
+    LOG(LOGS_WARN, "Could not open keyfile %s", key_file);
+    return;
+  }
+
+  while (fgets(line, sizeof (line), in)) {
+    line_number++;
+
+    CPS_NormalizeLine(line);
+    if (!*line)
+      continue;
+
+    if (!CPS_ParseKey(line, &key_id, &hashname, &keyval)) {
+      LOG(LOGS_WARN, "Could not parse key at line %d in file %s", line_number, key_file);
+      continue;
+    }
+
+    key.hash_id = HSH_GetHashId(hashname);
+    if (key.hash_id < 0) {
+      LOG(LOGS_WARN, "Unknown hash function in key %"PRIu32, key_id);
+      continue;
+    }
+
+    key.len = decode_password(keyval);
+    if (!key.len) {
+      LOG(LOGS_WARN, "Could not decode password in key %"PRIu32, key_id);
+      continue;
+    }
+
+    key.id = key_id;
+    key.val = MallocArray(char, key.len);
+    memcpy(key.val, keyval, key.len);
+    ARR_AppendElement(keys, &key);
+  }
+
+  fclose(in);
+
+  /* Sort keys into order.  Note, if there's a duplicate, it is
+     arbitrary which one we use later - the user should have been
+     more careful! */
+  qsort(ARR_GetElements(keys), ARR_GetSize(keys), sizeof (Key), compare_keys_by_id);
+
+  /* Check for duplicates */
+  for (i = 1; i < ARR_GetSize(keys); i++) {
+    if (get_key(i - 1)->id == get_key(i)->id)
+      LOG(LOGS_WARN, "Detected duplicate key %"PRIu32, get_key(i - 1)->id);
+  }
+
+  /* Erase any passwords from stack */
+  memset(line, 0, sizeof (line));
+
+  for (i = 0; i < ARR_GetSize(keys); i++)
+    get_key(i)->auth_delay = determine_hash_delay(get_key(i)->id);
+}
+
+/* ================================================== */
+
+static int
+lookup_key(uint32_t id)
+{
+  Key specimen, *where, *keys_ptr;
+  int pos;
+
+  keys_ptr = ARR_GetElements(keys);
+  specimen.id = id;
+  where = (Key *)bsearch((void *)&specimen, keys_ptr, ARR_GetSize(keys),
+                         sizeof (Key), compare_keys_by_id);
+  if (!where) {
+    return -1;
+  } else {
+    pos = where - keys_ptr;
+    return pos;
+  }
+}
+
+/* ================================================== */
+
+static Key *
+get_key_by_id(uint32_t key_id)
+{
+  int position;
+
+  if (cache_valid && key_id == cache_key_id)
+    return get_key(cache_key_pos);
+
+  position = lookup_key(key_id);
+
+  if (position >= 0) {
+    cache_valid = 1;
+    cache_key_pos = position;
+    cache_key_id = key_id;
+
+    return get_key(position);
+  }
+
+  return NULL;
+}
+
+/* ================================================== */
+
+int
+KEY_KeyKnown(uint32_t key_id)
+{
+  return get_key_by_id(key_id) != NULL;
+}
+
+/* ================================================== */
+
+int
+KEY_GetAuthDelay(uint32_t key_id)
+{
+  Key *key;
+
+  key = get_key_by_id(key_id);
+
+  if (!key)
+    return 0;
+
+  return key->auth_delay;
+}
+
+/* ================================================== */
+
+int
+KEY_GetAuthLength(uint32_t key_id)
+{
+  unsigned char buf[MAX_HASH_LENGTH];
+  Key *key;
+
+  key = get_key_by_id(key_id);
+
+  if (!key)
+    return 0;
+
+  return HSH_Hash(key->hash_id, buf, 0, buf, 0, buf, sizeof (buf));
+}
+
+/* ================================================== */
+
+int
+KEY_CheckKeyLength(uint32_t key_id)
+{
+  Key *key;
+
+  key = get_key_by_id(key_id);
+
+  if (!key)
+    return 0;
+
+  return key->len >= MIN_SECURE_KEY_LENGTH;
+}
+
+/* ================================================== */
+
+static int
+generate_ntp_auth(int hash_id, const unsigned char *key, int key_len,
+                  const unsigned char *data, int data_len,
+                  unsigned char *auth, int auth_len)
+{
+  return HSH_Hash(hash_id, key, key_len, data, data_len, auth, auth_len);
+}
+
+/* ================================================== */
+
+static int
+check_ntp_auth(int hash_id, const unsigned char *key, int key_len,
+               const unsigned char *data, int data_len,
+               const unsigned char *auth, int auth_len, int trunc_len)
+{
+  unsigned char buf[MAX_HASH_LENGTH];
+  int hash_len;
+
+  hash_len = generate_ntp_auth(hash_id, key, key_len, data, data_len, buf, sizeof (buf));
+
+  return MIN(hash_len, trunc_len) == auth_len && !memcmp(buf, auth, auth_len);
+}
+
+/* ================================================== */
+
+int
+KEY_GenerateAuth(uint32_t key_id, const unsigned char *data, int data_len,
+    unsigned char *auth, int auth_len)
+{
+  Key *key;
+
+  key = get_key_by_id(key_id);
+
+  if (!key)
+    return 0;
+
+  return generate_ntp_auth(key->hash_id, (unsigned char *)key->val, key->len,
+                           data, data_len, auth, auth_len);
+}
+
+/* ================================================== */
+
+int
+KEY_CheckAuth(uint32_t key_id, const unsigned char *data, int data_len,
+              const unsigned char *auth, int auth_len, int trunc_len)
+{
+  Key *key;
+
+  key = get_key_by_id(key_id);
+
+  if (!key)
+    return 0;
+
+  return check_ntp_auth(key->hash_id, (unsigned char *)key->val, key->len,
+                        data, data_len, auth, auth_len, trunc_len);
+}
diff --git a/chrony_3_3/keys.h b/chrony_3_3/keys.h
new file mode 100644
index 0000000..82f3a26
--- /dev/null
+++ b/chrony_3_3/keys.h
@@ -0,0 +1,48 @@
+/*
+  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 for key management module
+  */
+
+#ifndef GOT_KEYS_H
+#define GOT_KEYS_H
+
+#include "sysincl.h"
+
+extern void KEY_Initialise(void);
+extern void KEY_Finalise(void);
+
+extern void KEY_Reload(void);
+
+extern int KEY_GetKey(uint32_t key_id, char **key, int *len);
+extern int KEY_KeyKnown(uint32_t key_id);
+extern int KEY_GetAuthDelay(uint32_t key_id);
+extern int KEY_GetAuthLength(uint32_t key_id);
+extern int KEY_CheckKeyLength(uint32_t key_id);
+
+extern int KEY_GenerateAuth(uint32_t key_id, const unsigned char *data,
+    int data_len, unsigned char *auth, int auth_len);
+extern int KEY_CheckAuth(uint32_t key_id, const unsigned char *data, int data_len,
+                         const unsigned char *auth, int auth_len, int trunc_len);
+
+#endif /* GOT_KEYS_H */
diff --git a/chrony_3_3/linux-errqueue.h b/chrony_3_3/linux-errqueue.h
new file mode 100644
index 0000000..69a7291
--- /dev/null
+++ b/chrony_3_3/linux-errqueue.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_ERRQUEUE_H
+#define _LINUX_ERRQUEUE_H
+
+#include <linux/types.h>
+#include <time.h>
+
+struct sock_extended_err {
+	__u32	ee_errno;	
+	__u8	ee_origin;
+	__u8	ee_type;
+	__u8	ee_code;
+	__u8	ee_pad;
+	__u32   ee_info;
+	__u32   ee_data;
+};
+
+#define SO_EE_ORIGIN_NONE	0
+#define SO_EE_ORIGIN_LOCAL	1
+#define SO_EE_ORIGIN_ICMP	2
+#define SO_EE_ORIGIN_ICMP6	3
+#define SO_EE_ORIGIN_TXSTATUS	4
+#define SO_EE_ORIGIN_ZEROCOPY	5
+#define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS
+
+#define SO_EE_OFFENDER(ee)	((struct sockaddr*)((ee)+1))
+
+#define SO_EE_CODE_ZEROCOPY_COPIED	1
+
+/**
+ *	struct scm_timestamping - timestamps exposed through cmsg
+ *
+ *	The timestamping interfaces SO_TIMESTAMPING, MSG_TSTAMP_*
+ *	communicate network timestamps by passing this struct in a cmsg with
+ *	recvmsg(). See Documentation/networking/timestamping.txt for details.
+ */
+struct scm_timestamping {
+	struct timespec ts[3];
+};
+
+/* The type of scm_timestamping, passed in sock_extended_err ee_info.
+ * This defines the type of ts[0]. For SCM_TSTAMP_SND only, if ts[0]
+ * is zero, then this is a hardware timestamp and recorded in ts[2].
+ */
+enum {
+	SCM_TSTAMP_SND,		/* driver passed skb to NIC, or HW */
+	SCM_TSTAMP_SCHED,	/* data entered the packet scheduler */
+	SCM_TSTAMP_ACK,		/* data acknowledged by peer */
+};
+
+#endif /* _LINUX_ERRQUEUE_H */
diff --git a/chrony_3_3/linux-net_tstamp.h b/chrony_3_3/linux-net_tstamp.h
new file mode 100644
index 0000000..4fe104b
--- /dev/null
+++ b/chrony_3_3/linux-net_tstamp.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Userspace API for hardware time stamping of network packets
+ *
+ * Copyright (C) 2008,2009 Intel Corporation
+ * Author: Patrick Ohly <patrick.ohly@intel.com>
+ *
+ */
+
+#ifndef _NET_TIMESTAMPING_H
+#define _NET_TIMESTAMPING_H
+
+#include <linux/types.h>
+#include <linux/socket.h>   /* for SO_TIMESTAMPING */
+
+/* SO_TIMESTAMPING gets an integer bit field comprised of these values */
+enum {
+	SOF_TIMESTAMPING_TX_HARDWARE = (1<<0),
+	SOF_TIMESTAMPING_TX_SOFTWARE = (1<<1),
+	SOF_TIMESTAMPING_RX_HARDWARE = (1<<2),
+	SOF_TIMESTAMPING_RX_SOFTWARE = (1<<3),
+	SOF_TIMESTAMPING_SOFTWARE = (1<<4),
+	SOF_TIMESTAMPING_SYS_HARDWARE = (1<<5),
+	SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6),
+	SOF_TIMESTAMPING_OPT_ID = (1<<7),
+	SOF_TIMESTAMPING_TX_SCHED = (1<<8),
+	SOF_TIMESTAMPING_TX_ACK = (1<<9),
+	SOF_TIMESTAMPING_OPT_CMSG = (1<<10),
+	SOF_TIMESTAMPING_OPT_TSONLY = (1<<11),
+	SOF_TIMESTAMPING_OPT_STATS = (1<<12),
+	SOF_TIMESTAMPING_OPT_PKTINFO = (1<<13),
+	SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14),
+
+	SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_TX_SWHW,
+	SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
+				 SOF_TIMESTAMPING_LAST
+};
+
+/*
+ * SO_TIMESTAMPING flags are either for recording a packet timestamp or for
+ * reporting the timestamp to user space.
+ * Recording flags can be set both via socket options and control messages.
+ */
+#define SOF_TIMESTAMPING_TX_RECORD_MASK	(SOF_TIMESTAMPING_TX_HARDWARE | \
+					 SOF_TIMESTAMPING_TX_SOFTWARE | \
+					 SOF_TIMESTAMPING_TX_SCHED | \
+					 SOF_TIMESTAMPING_TX_ACK)
+
+/**
+ * struct hwtstamp_config - %SIOCGHWTSTAMP and %SIOCSHWTSTAMP parameter
+ *
+ * @flags:	no flags defined right now, must be zero for %SIOCSHWTSTAMP
+ * @tx_type:	one of HWTSTAMP_TX_*
+ * @rx_filter:	one of HWTSTAMP_FILTER_*
+ *
+ * %SIOCGHWTSTAMP and %SIOCSHWTSTAMP expect a &struct ifreq with a
+ * ifr_data pointer to this structure.  For %SIOCSHWTSTAMP, if the
+ * driver or hardware does not support the requested @rx_filter value,
+ * the driver may use a more general filter mode.  In this case
+ * @rx_filter will indicate the actual mode on return.
+ */
+struct hwtstamp_config {
+	int flags;
+	int tx_type;
+	int rx_filter;
+};
+
+/* possible values for hwtstamp_config->tx_type */
+enum hwtstamp_tx_types {
+	/*
+	 * No outgoing packet will need hardware time stamping;
+	 * should a packet arrive which asks for it, no hardware
+	 * time stamping will be done.
+	 */
+	HWTSTAMP_TX_OFF,
+
+	/*
+	 * Enables hardware time stamping for outgoing packets;
+	 * the sender of the packet decides which are to be
+	 * time stamped by setting %SOF_TIMESTAMPING_TX_SOFTWARE
+	 * before sending the packet.
+	 */
+	HWTSTAMP_TX_ON,
+
+	/*
+	 * Enables time stamping for outgoing packets just as
+	 * HWTSTAMP_TX_ON does, but also enables time stamp insertion
+	 * directly into Sync packets. In this case, transmitted Sync
+	 * packets will not received a time stamp via the socket error
+	 * queue.
+	 */
+	HWTSTAMP_TX_ONESTEP_SYNC,
+};
+
+/* possible values for hwtstamp_config->rx_filter */
+enum hwtstamp_rx_filters {
+	/* time stamp no incoming packet at all */
+	HWTSTAMP_FILTER_NONE,
+
+	/* time stamp any incoming packet */
+	HWTSTAMP_FILTER_ALL,
+
+	/* return value: time stamp all packets requested plus some others */
+	HWTSTAMP_FILTER_SOME,
+
+	/* PTP v1, UDP, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V1_L4_EVENT,
+	/* PTP v1, UDP, Sync packet */
+	HWTSTAMP_FILTER_PTP_V1_L4_SYNC,
+	/* PTP v1, UDP, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ,
+	/* PTP v2, UDP, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V2_L4_EVENT,
+	/* PTP v2, UDP, Sync packet */
+	HWTSTAMP_FILTER_PTP_V2_L4_SYNC,
+	/* PTP v2, UDP, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ,
+
+	/* 802.AS1, Ethernet, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V2_L2_EVENT,
+	/* 802.AS1, Ethernet, Sync packet */
+	HWTSTAMP_FILTER_PTP_V2_L2_SYNC,
+	/* 802.AS1, Ethernet, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ,
+
+	/* PTP v2/802.AS1, any layer, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V2_EVENT,
+	/* PTP v2/802.AS1, any layer, Sync packet */
+	HWTSTAMP_FILTER_PTP_V2_SYNC,
+	/* PTP v2/802.AS1, any layer, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V2_DELAY_REQ,
+
+	/* NTP, UDP, all versions and packet modes */
+	HWTSTAMP_FILTER_NTP_ALL,
+};
+
+/* SCM_TIMESTAMPING_PKTINFO control message */
+struct scm_ts_pktinfo {
+	__u32 if_index;
+	__u32 pkt_length;
+	__u32 reserved[2];
+};
+
+#endif /* _NET_TIMESTAMPING_H */
diff --git a/chrony_3_3/local.c b/chrony_3_3/local.c
new file mode 100644
index 0000000..b4baaac
--- /dev/null
+++ b/chrony_3_3/local.c
@@ -0,0 +1,748 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2011, 2014-2015
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  The routines in this file present a common local (system) clock
+  interface to the rest of the software.
+
+  They interface with the system specific driver files in sys_*.c
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "conf.h"
+#include "local.h"
+#include "localp.h"
+#include "memory.h"
+#include "smooth.h"
+#include "util.h"
+#include "logging.h"
+
+/* ================================================== */
+
+/* Variable to store the current frequency, in ppm */
+static double current_freq_ppm;
+
+/* Maximum allowed frequency, in ppm */
+static double max_freq_ppm;
+
+/* Temperature compensation, in ppm */
+static double temp_comp_ppm;
+
+/* ================================================== */
+/* Store the system dependent drivers */
+
+static lcl_ReadFrequencyDriver drv_read_freq;
+static lcl_SetFrequencyDriver drv_set_freq;
+static lcl_AccrueOffsetDriver drv_accrue_offset;
+static lcl_ApplyStepOffsetDriver drv_apply_step_offset;
+static lcl_OffsetCorrectionDriver drv_offset_convert;
+static lcl_SetLeapDriver drv_set_leap;
+static lcl_SetSyncStatusDriver drv_set_sync_status;
+
+/* ================================================== */
+
+/* Types and variables associated with handling the parameter change
+   list */
+
+typedef struct _ChangeListEntry {
+  struct _ChangeListEntry *next;
+  struct _ChangeListEntry *prev;
+  LCL_ParameterChangeHandler handler;
+  void *anything;
+} ChangeListEntry;
+
+static ChangeListEntry change_list;
+
+/* ================================================== */
+
+/* Types and variables associated with handling the parameter change
+   list */
+
+typedef struct _DispersionNotifyListEntry {
+  struct _DispersionNotifyListEntry *next;
+  struct _DispersionNotifyListEntry *prev;
+  LCL_DispersionNotifyHandler handler;
+  void *anything;
+} DispersionNotifyListEntry;
+
+static DispersionNotifyListEntry dispersion_notify_list;
+
+/* ================================================== */
+
+static int precision_log;
+static double precision_quantum;
+
+static double max_clock_error;
+
+/* ================================================== */
+
+/* Define the number of increments of the system clock that we want
+   to see to be fairly sure that we've got something approaching
+   the minimum increment.  Even on a crummy implementation that can't
+   interpolate between 10ms ticks, we should get this done in
+   under 1s of busy waiting. */
+#define NITERS 100
+
+#define NSEC_PER_SEC 1000000000
+
+static void
+calculate_sys_precision(void)
+{
+  struct timespec ts, old_ts;
+  int iters, diff, best;
+
+  LCL_ReadRawTime(&old_ts);
+
+  /* Assume we must be better than a second */
+  best = NSEC_PER_SEC;
+  iters = 0;
+
+  do {
+    LCL_ReadRawTime(&ts);
+
+    diff = NSEC_PER_SEC * (ts.tv_sec - old_ts.tv_sec) + (ts.tv_nsec - old_ts.tv_nsec);
+
+    old_ts = ts;
+    if (diff > 0) {
+      if (diff < best)
+        best = diff;
+      iters++;
+    }
+  } while (iters < NITERS);
+
+  assert(best > 0);
+
+  precision_quantum = 1.0e-9 * best;
+
+  /* Get rounded log2 value of the measured precision */
+  precision_log = 0;
+  while (best < 707106781) {
+    precision_log--;
+    best *= 2;
+  }
+
+  assert(precision_log >= -30);
+
+  DEBUG_LOG("Clock precision %.9f (%d)", precision_quantum, precision_log);
+}
+
+/* ================================================== */
+
+void
+LCL_Initialise(void)
+{
+  change_list.next = change_list.prev = &change_list;
+
+  dispersion_notify_list.next = dispersion_notify_list.prev = &dispersion_notify_list;
+
+  /* Null out the system drivers, so that we die
+     if they never get defined before use */
+  
+  drv_read_freq = NULL;
+  drv_set_freq = NULL;
+  drv_accrue_offset = NULL;
+  drv_offset_convert = NULL;
+
+  /* This ought to be set from the system driver layer */
+  current_freq_ppm = 0.0;
+  temp_comp_ppm = 0.0;
+
+  calculate_sys_precision();
+
+  /* This is the maximum allowed frequency offset in ppm, the time must
+     never stop or run backwards */
+  max_freq_ppm = CNF_GetMaxDrift();
+  max_freq_ppm = CLAMP(0.0, max_freq_ppm, 500000.0);
+
+  max_clock_error = CNF_GetMaxClockError() * 1e-6;
+}
+
+/* ================================================== */
+
+void
+LCL_Finalise(void)
+{
+  while (change_list.next != &change_list)
+    LCL_RemoveParameterChangeHandler(change_list.next->handler,
+                                     change_list.next->anything);
+
+  while (dispersion_notify_list.next != &dispersion_notify_list)
+    LCL_RemoveDispersionNotifyHandler(dispersion_notify_list.next->handler,
+                                      dispersion_notify_list.next->anything);
+}
+
+/* ================================================== */
+
+/* Routine to read the system precision as a log to base 2 value. */
+int
+LCL_GetSysPrecisionAsLog(void)
+{
+  return precision_log;
+}
+
+/* ================================================== */
+/* Routine to read the system precision in terms of the actual time step */
+
+double
+LCL_GetSysPrecisionAsQuantum(void)
+{
+  return precision_quantum;
+}
+
+/* ================================================== */
+
+double
+LCL_GetMaxClockError(void)
+{
+  return max_clock_error;
+}
+
+/* ================================================== */
+
+void
+LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything)
+{
+  ChangeListEntry *ptr, *new_entry;
+
+  /* Check that the handler is not already registered */
+  for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
+    if (!(ptr->handler != handler || ptr->anything != anything)) {
+      assert(0);
+    }
+  }
+
+  new_entry = MallocNew(ChangeListEntry);
+
+  new_entry->handler = handler;
+  new_entry->anything = anything;
+
+  /* Chain it into the list */
+  new_entry->next = &change_list;
+  new_entry->prev = change_list.prev;
+  change_list.prev->next = new_entry;
+  change_list.prev = new_entry;
+}
+
+/* ================================================== */
+
+/* Remove a handler */
+void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything)
+{
+
+  ChangeListEntry *ptr;
+  int ok;
+
+  ptr = NULL;
+  ok = 0;
+
+  for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
+    if (ptr->handler == handler && ptr->anything == anything) {
+      ok = 1;
+      break;
+    }
+  }
+
+  assert(ok);
+
+  /* Unlink entry from the list */
+  ptr->next->prev = ptr->prev;
+  ptr->prev->next = ptr->next;
+
+  Free(ptr);
+}
+
+/* ================================================== */
+
+int
+LCL_IsFirstParameterChangeHandler(LCL_ParameterChangeHandler handler)
+{
+  return change_list.next->handler == handler;
+}
+
+/* ================================================== */
+
+static void
+invoke_parameter_change_handlers(struct timespec *raw, struct timespec *cooked,
+                                 double dfreq, double doffset,
+                                 LCL_ChangeType change_type)
+{
+  ChangeListEntry *ptr;
+
+  for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
+    (ptr->handler)(raw, cooked, dfreq, doffset, change_type, ptr->anything);
+  }
+}
+
+/* ================================================== */
+
+void
+LCL_AddDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anything)
+{
+  DispersionNotifyListEntry *ptr, *new_entry;
+
+  /* Check that the handler is not already registered */
+  for (ptr = dispersion_notify_list.next; ptr != &dispersion_notify_list; ptr = ptr->next) {
+    if (!(ptr->handler != handler || ptr->anything != anything)) {
+      assert(0);
+    }
+  }
+
+  new_entry = MallocNew(DispersionNotifyListEntry);
+
+  new_entry->handler = handler;
+  new_entry->anything = anything;
+
+  /* Chain it into the list */
+  new_entry->next = &dispersion_notify_list;
+  new_entry->prev = dispersion_notify_list.prev;
+  dispersion_notify_list.prev->next = new_entry;
+  dispersion_notify_list.prev = new_entry;
+}
+
+/* ================================================== */
+
+/* Remove a handler */
+extern 
+void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anything)
+{
+
+  DispersionNotifyListEntry *ptr;
+  int ok;
+
+  ptr = NULL;
+  ok = 0;
+
+  for (ptr = dispersion_notify_list.next; ptr != &dispersion_notify_list; ptr = ptr->next) {
+    if (ptr->handler == handler && ptr->anything == anything) {
+      ok = 1;
+      break;
+    }
+  }
+
+  assert(ok);
+
+  /* Unlink entry from the list */
+  ptr->next->prev = ptr->prev;
+  ptr->prev->next = ptr->next;
+
+  Free(ptr);
+}
+
+/* ================================================== */
+
+void
+LCL_ReadRawTime(struct timespec *ts)
+{
+#if HAVE_CLOCK_GETTIME
+  if (clock_gettime(CLOCK_REALTIME, ts) < 0)
+    LOG_FATAL("clock_gettime() failed : %s", strerror(errno));
+#else
+  struct timeval tv;
+
+  if (gettimeofday(&tv, NULL) < 0)
+    LOG_FATAL("gettimeofday() failed : %s", strerror(errno));
+
+  UTI_TimevalToTimespec(&tv, ts);
+#endif
+}
+
+/* ================================================== */
+
+void
+LCL_ReadCookedTime(struct timespec *result, double *err)
+{
+  struct timespec raw;
+
+  LCL_ReadRawTime(&raw);
+  LCL_CookTime(&raw, result, err);
+}
+
+/* ================================================== */
+
+void
+LCL_CookTime(struct timespec *raw, struct timespec *cooked, double *err)
+{
+  double correction;
+
+  LCL_GetOffsetCorrection(raw, &correction, err);
+  UTI_AddDoubleToTimespec(raw, correction, cooked);
+}
+
+/* ================================================== */
+
+void
+LCL_GetOffsetCorrection(struct timespec *raw, double *correction, double *err)
+{
+  /* Call system specific driver to get correction */
+  (*drv_offset_convert)(raw, correction, err);
+}
+
+/* ================================================== */
+/* Return current frequency */
+
+double
+LCL_ReadAbsoluteFrequency(void)
+{
+  double freq;
+
+  freq = current_freq_ppm; 
+
+  /* Undo temperature compensation */
+  if (temp_comp_ppm != 0.0) {
+    freq = (freq + temp_comp_ppm) / (1.0 - 1.0e-6 * temp_comp_ppm);
+  }
+
+  return freq;
+}
+
+/* ================================================== */
+
+static double
+clamp_freq(double freq)
+{
+  if (freq <= max_freq_ppm && freq >= -max_freq_ppm)
+    return freq;
+
+  LOG(LOGS_WARN, "Frequency %.1f ppm exceeds allowed maximum", freq);
+
+  return CLAMP(-max_freq_ppm, freq, max_freq_ppm);
+}
+
+/* ================================================== */
+
+static int
+check_offset(struct timespec *now, double offset)
+{
+  /* Check if the time will be still sane with accumulated offset */
+  if (UTI_IsTimeOffsetSane(now, -offset))
+      return 1;
+
+  LOG(LOGS_WARN, "Adjustment of %.1f seconds is invalid", -offset);
+  return 0;
+}
+
+/* ================================================== */
+
+/* This involves both setting the absolute frequency with the
+   system-specific driver, as well as calling all notify handlers */
+
+void
+LCL_SetAbsoluteFrequency(double afreq_ppm)
+{
+  struct timespec raw, cooked;
+  double dfreq;
+  
+  afreq_ppm = clamp_freq(afreq_ppm);
+
+  /* Apply temperature compensation */
+  if (temp_comp_ppm != 0.0) {
+    afreq_ppm = afreq_ppm * (1.0 - 1.0e-6 * temp_comp_ppm) - temp_comp_ppm;
+  }
+
+  /* Call the system-specific driver for setting the frequency */
+  
+  afreq_ppm = (*drv_set_freq)(afreq_ppm);
+
+  dfreq = (afreq_ppm - current_freq_ppm) / (1.0e6 - current_freq_ppm);
+
+  LCL_ReadRawTime(&raw);
+  LCL_CookTime(&raw, &cooked, NULL);
+
+  /* Dispatch to all handlers */
+  invoke_parameter_change_handlers(&raw, &cooked, dfreq, 0.0, LCL_ChangeAdjust);
+
+  current_freq_ppm = afreq_ppm;
+
+}
+
+/* ================================================== */
+
+void
+LCL_AccumulateDeltaFrequency(double dfreq)
+{
+  struct timespec raw, cooked;
+  double old_freq_ppm;
+
+  old_freq_ppm = current_freq_ppm;
+
+  /* Work out new absolute frequency.  Note that absolute frequencies
+   are handled in units of ppm, whereas the 'dfreq' argument is in
+   terms of the gradient of the (offset) v (local time) function. */
+
+  current_freq_ppm += dfreq * (1.0e6 - current_freq_ppm);
+
+  current_freq_ppm = clamp_freq(current_freq_ppm);
+
+  /* Call the system-specific driver for setting the frequency */
+  current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
+  dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 - old_freq_ppm);
+
+  LCL_ReadRawTime(&raw);
+  LCL_CookTime(&raw, &cooked, NULL);
+
+  /* Dispatch to all handlers */
+  invoke_parameter_change_handlers(&raw, &cooked, dfreq, 0.0, LCL_ChangeAdjust);
+}
+
+/* ================================================== */
+
+void
+LCL_AccumulateOffset(double offset, double corr_rate)
+{
+  struct timespec raw, cooked;
+
+  /* In this case, the cooked time to be passed to the notify clients
+     has to be the cooked time BEFORE the change was made */
+
+  LCL_ReadRawTime(&raw);
+  LCL_CookTime(&raw, &cooked, NULL);
+
+  if (!check_offset(&cooked, offset))
+      return;
+
+  (*drv_accrue_offset)(offset, corr_rate);
+
+  /* Dispatch to all handlers */
+  invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeAdjust);
+}
+
+/* ================================================== */
+
+int
+LCL_ApplyStepOffset(double offset)
+{
+  struct timespec raw, cooked;
+
+  /* In this case, the cooked time to be passed to the notify clients
+     has to be the cooked time BEFORE the change was made */
+
+  LCL_ReadRawTime(&raw);
+  LCL_CookTime(&raw, &cooked, NULL);
+
+  if (!check_offset(&raw, offset))
+      return 0;
+
+  if (!(*drv_apply_step_offset)(offset)) {
+    LOG(LOGS_ERR, "Could not step system clock");
+    return 0;
+  }
+
+  /* Reset smoothing on all clock steps */
+  SMT_Reset(&cooked);
+
+  /* Dispatch to all handlers */
+  invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeStep);
+
+  return 1;
+}
+
+/* ================================================== */
+
+void
+LCL_NotifyExternalTimeStep(struct timespec *raw, struct timespec *cooked,
+    double offset, double dispersion)
+{
+  /* Dispatch to all handlers */
+  invoke_parameter_change_handlers(raw, cooked, 0.0, offset, LCL_ChangeUnknownStep);
+
+  lcl_InvokeDispersionNotifyHandlers(dispersion);
+}
+
+/* ================================================== */
+
+void
+LCL_NotifyLeap(int leap)
+{
+  struct timespec raw, cooked;
+
+  LCL_ReadRawTime(&raw);
+  LCL_CookTime(&raw, &cooked, NULL);
+
+  /* Smooth the leap second out */
+  SMT_Leap(&cooked, leap);
+
+  /* Dispatch to all handlers as if the clock was stepped */
+  invoke_parameter_change_handlers(&raw, &cooked, 0.0, -leap, LCL_ChangeStep);
+}
+
+/* ================================================== */
+
+void
+LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
+{
+  struct timespec raw, cooked;
+  double old_freq_ppm;
+
+  LCL_ReadRawTime(&raw);
+  /* Due to modifying the offset, this has to be the cooked time prior
+     to the change we are about to make */
+  LCL_CookTime(&raw, &cooked, NULL);
+
+  if (!check_offset(&cooked, doffset))
+      return;
+
+  old_freq_ppm = current_freq_ppm;
+
+  /* Work out new absolute frequency.  Note that absolute frequencies
+   are handled in units of ppm, whereas the 'dfreq' argument is in
+   terms of the gradient of the (offset) v (local time) function. */
+  current_freq_ppm += dfreq * (1.0e6 - current_freq_ppm);
+
+  current_freq_ppm = clamp_freq(current_freq_ppm);
+
+  DEBUG_LOG("old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
+      old_freq_ppm, current_freq_ppm, doffset);
+
+  /* Call the system-specific driver for setting the frequency */
+  current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
+  dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 - old_freq_ppm);
+
+  (*drv_accrue_offset)(doffset, corr_rate);
+
+  /* Dispatch to all handlers */
+  invoke_parameter_change_handlers(&raw, &cooked, dfreq, doffset, LCL_ChangeAdjust);
+}
+
+/* ================================================== */
+
+void
+lcl_InvokeDispersionNotifyHandlers(double dispersion)
+{
+  DispersionNotifyListEntry *ptr;
+
+  for (ptr = dispersion_notify_list.next; ptr != &dispersion_notify_list; ptr = ptr->next) {
+    (ptr->handler)(dispersion, ptr->anything);
+  }
+
+}
+
+/* ================================================== */
+
+void
+lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
+                          lcl_SetFrequencyDriver set_freq,
+                          lcl_AccrueOffsetDriver accrue_offset,
+                          lcl_ApplyStepOffsetDriver apply_step_offset,
+                          lcl_OffsetCorrectionDriver offset_convert,
+                          lcl_SetLeapDriver set_leap,
+                          lcl_SetSyncStatusDriver set_sync_status)
+{
+  drv_read_freq = read_freq;
+  drv_set_freq = set_freq;
+  drv_accrue_offset = accrue_offset;
+  drv_apply_step_offset = apply_step_offset;
+  drv_offset_convert = offset_convert;
+  drv_set_leap = set_leap;
+  drv_set_sync_status = set_sync_status;
+
+  current_freq_ppm = (*drv_read_freq)();
+
+  DEBUG_LOG("Local freq=%.3fppm", current_freq_ppm);
+}
+
+/* ================================================== */
+/* Look at the current difference between the system time and the NTP
+   time, and make a step to cancel it. */
+
+int
+LCL_MakeStep(void)
+{
+  struct timespec raw;
+  double correction;
+
+  LCL_ReadRawTime(&raw);
+  LCL_GetOffsetCorrection(&raw, &correction, NULL);
+
+  if (!check_offset(&raw, -correction))
+      return 0;
+
+  /* Cancel remaining slew and make the step */
+  LCL_AccumulateOffset(correction, 0.0);
+  if (!LCL_ApplyStepOffset(-correction))
+    return 0;
+
+  LOG(LOGS_WARN, "System clock was stepped by %.6f seconds", correction);
+
+  return 1;
+}
+
+/* ================================================== */
+
+int
+LCL_CanSystemLeap(void)
+{
+  return drv_set_leap ? 1 : 0;
+}
+
+/* ================================================== */
+
+void
+LCL_SetSystemLeap(int leap, int tai_offset)
+{
+  if (drv_set_leap) {
+    (drv_set_leap)(leap, tai_offset);
+  }
+}
+
+/* ================================================== */
+
+double
+LCL_SetTempComp(double comp)
+{
+  double uncomp_freq_ppm;
+
+  if (temp_comp_ppm == comp)
+    return comp;
+
+  /* Undo previous compensation */
+  current_freq_ppm = (current_freq_ppm + temp_comp_ppm) /
+    (1.0 - 1.0e-6 * temp_comp_ppm);
+
+  uncomp_freq_ppm = current_freq_ppm;
+
+  /* Apply new compensation */
+  current_freq_ppm = current_freq_ppm * (1.0 - 1.0e-6 * comp) - comp;
+
+  /* Call the system-specific driver for setting the frequency */
+  current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
+
+  temp_comp_ppm = (uncomp_freq_ppm - current_freq_ppm) /
+    (1.0e-6 * uncomp_freq_ppm + 1.0);
+
+  return temp_comp_ppm;
+}
+
+/* ================================================== */
+
+void
+LCL_SetSyncStatus(int synchronised, double est_error, double max_error)
+{
+  if (drv_set_sync_status) {
+    (drv_set_sync_status)(synchronised, est_error, max_error);
+  }
+}
+
+/* ================================================== */
diff --git a/chrony_3_3/local.h b/chrony_3_3/local.h
new file mode 100644
index 0000000..7ceb76a
--- /dev/null
+++ b/chrony_3_3/local.h
@@ -0,0 +1,221 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  This module provides an interface to the system time, and
+  insulates the rest of the program from the different way
+  that interface has to be done on various operating systems.
+  */
+
+#ifndef GOT_LOCAL_H
+#define GOT_LOCAL_H
+
+#include "sysincl.h"
+
+/* Read the system clock */
+extern void LCL_ReadRawTime(struct timespec *ts);
+
+/* Read the system clock, corrected according to all accumulated
+   drifts and uncompensated offsets.
+
+   In a kernel implementation with vernier frequency control (like
+   Linux), and if we were to apply offsets by stepping the clock, this
+   would be identical to raw time.  In any other case (use of
+   adjtime()-like interface to correct offsets, and to adjust the
+   frequency), we must correct the raw time to get this value */
+
+extern void LCL_ReadCookedTime(struct timespec *ts, double *err);
+
+/* Convert raw time to cooked. */
+extern void LCL_CookTime(struct timespec *raw, struct timespec *cooked, double *err);
+
+/* Read the current offset between the system clock and true time
+   (i.e. 'cooked' - 'raw') (in seconds). */
+
+extern void LCL_GetOffsetCorrection(struct timespec *raw, double *correction, double *err);
+
+/* Type of routines that may be invoked as callbacks when there is a
+   change to the frequency or offset.
+
+   raw : raw local clock time at which change occurred
+
+   cooked : cooked local time at which change occurred
+
+   dfreq : delta frequency relative to previous value (in terms of
+   seconds gained by system clock per unit system clock time)
+
+   doffset : delta offset applied (positive => make local system fast
+   by that amount, negative => make it slow by that amount)
+
+   change_type : what type of change is being applied
+   
+   anything : Passthrough argument from call to registration routine */
+
+
+typedef enum {
+  LCL_ChangeAdjust,
+  LCL_ChangeStep,
+  LCL_ChangeUnknownStep
+} LCL_ChangeType;
+
+typedef void (*LCL_ParameterChangeHandler)
+     (struct timespec *raw, struct timespec *cooked,
+      double dfreq,
+      double doffset,
+      LCL_ChangeType change_type,
+      void *anything
+      );
+
+/* Add a handler.  Then handler MUST NOT deregister itself!!! */
+extern void LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything);
+
+/* Remove a handler */
+extern void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler, void *anything);
+
+/* Check if a handler is invoked first when dispatching */
+extern int LCL_IsFirstParameterChangeHandler(LCL_ParameterChangeHandler handler);
+
+/* Function type for handlers to be called back when an indeterminate
+   offset is introduced into the local time.  This situation occurs
+   when the frequency must be adjusted to effect a clock slew and
+   there is doubt about one of the endpoints of the interval over
+   which the frequency change was applied.It is expected that such
+   handlers will add extra dispersion to any existing samples stored
+   in their registers. 
+
+   dispersion : The bound on how much error has been introduced in the
+   local clock, in seconds.
+
+   anything : passthrough from the registration routine
+
+   */
+
+typedef void (*LCL_DispersionNotifyHandler)(double dispersion, void *anything);
+
+/* Register a handler for being notified of dispersion being added to
+   the local clock.  The handler MUST NOT unregister itself!!! */
+
+extern void LCL_AddDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anything);
+
+/* Delete a handler */
+
+extern void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anything);
+
+
+/* Read the absolute system frequency, relative to the uncompensated
+   system.  Returned in units of parts per million.  Thus the result of
+   this is how many seconds fast the uncompensated system would be after
+   its own time has reached 1 million seconds from the start of the
+   measurement.  */
+extern double LCL_ReadAbsoluteFrequency(void);
+
+/* Routine to set the absolute frequency.  Only expected to be used
+   when either (i) reading the drift from a file at the start of a
+   run, or (ii) responsing to a user parameter 'poke'.  This is
+   defined in ppm, as for the absolute frequency reading routine. */
+
+extern void LCL_SetAbsoluteFrequency(double afreq);
+
+/* Routine to apply a change of frequency to the local clock.  The
+   argument is the estimated gain (positive) or loss (negative) of the
+   local clock relative to true time, per unit time of the PREVIOUS
+   frequency setting of the local clock.  This is assumed to be based
+   on a regression of y=offset v x=cooked local time. */
+
+extern void LCL_AccumulateDeltaFrequency(double dfreq);
+
+/* Routine to apply an offset (in seconds) to the local clock.  The
+   argument should be positive to move the clock backwards (i.e. the
+   local clock is currently fast of true time), or negative to move it
+   forwards (i.e. it is currently slow of true time).  Provided is also
+   a suggested correction rate (correction time * offset). */
+
+extern void LCL_AccumulateOffset(double offset, double corr_rate);
+
+/* Routine to apply an immediate offset by doing a sudden step if
+   possible. (Intended for use after an initial estimate of offset has
+   been obtained, so that we don't end up using adjtime to achieve a
+   slew of an hour or something like that). A positive argument means
+   the system clock is fast on true time, i.e. it needs to be stepped
+   backwards. (Same convention as for AccumulateOffset routine). */
+
+extern int LCL_ApplyStepOffset(double offset);
+
+/* Routine to invoke notify handlers on an unexpected time jump
+   in system clock */
+extern void LCL_NotifyExternalTimeStep(struct timespec *raw, struct timespec *cooked,
+    double offset, double dispersion);
+
+/* Routine to invoke notify handlers on leap second when the system clock
+   doesn't correct itself */
+extern void LCL_NotifyLeap(int leap);
+
+/* Perform the combination of modifying the frequency and applying
+   a slew, in one easy step */
+extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
+
+/* Routine to read the system precision as a log to base 2 value. */
+extern int LCL_GetSysPrecisionAsLog(void);
+
+/* Routine to read the system precision in terms of the actual time step */
+extern double LCL_GetSysPrecisionAsQuantum(void);
+
+/* Routine to read the maximum frequency error of the local clock.  This
+   is a frequency stability, not an absolute error. */
+extern double LCL_GetMaxClockError(void);
+
+/* Routine to initialise the module (to be called once at program
+   start-up) */
+
+extern void LCL_Initialise(void);
+
+/* Routine to finalise the module (to be called once at end of
+   run). */
+extern void LCL_Finalise(void);
+
+/* Routine to convert the outstanding system clock error to a step and
+   apply it, e.g. if the system clock has ended up an hour wrong due
+   to a timezone problem. */
+extern int LCL_MakeStep(void);
+
+/* Check if the system driver supports leap seconds, i.e. LCL_SetSystemLeap
+   does something */
+extern int LCL_CanSystemLeap(void);
+
+/* Routine to set the system clock to correct itself for a leap second and also
+   set its TAI-UTC offset.  If supported, leap second will be inserted at the
+   end of the day if the argument is positive, deleted if negative, and zero
+   resets the setting. */
+extern void LCL_SetSystemLeap(int leap, int tai_offset);
+
+/* Routine to set a frequency correction (in ppm) that should be applied
+   to local clock to compensate for temperature changes.  A positive
+   argument means that the clock frequency should be increased. Return the
+   actual compensation (may be different from the requested compensation
+   due to clamping or rounding). */
+extern double LCL_SetTempComp(double comp);
+
+/* Routine to update the synchronisation status in the kernel to allow other
+   applications to know if the system clock is synchronised and error bounds */
+extern void LCL_SetSyncStatus(int synchronised, double est_error, double max_error);
+
+#endif /* GOT_LOCAL_H */
diff --git a/chrony_3_3/localp.h b/chrony_3_3/localp.h
new file mode 100644
index 0000000..6f65e43
--- /dev/null
+++ b/chrony_3_3/localp.h
@@ -0,0 +1,74 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Private include file for local.c and all system dependent
+  driver modules.
+  */
+
+
+#ifndef GOT_LOCALP_H
+#define GOT_LOCALP_H
+
+/* System driver to read the current local frequency, in ppm relative
+   to nominal.  A positive value indicates that the local clock runs
+   fast when uncompensated. */
+typedef double (*lcl_ReadFrequencyDriver)(void);
+
+/* System driver to set the current local frequency, in ppm relative
+   to nominal.  A positive value indicates that the local clock runs
+   fast when uncompensated.  Return actual frequency (may be different
+   from the requested frequency due to clamping or rounding). */
+typedef double (*lcl_SetFrequencyDriver)(double freq_ppm);
+
+/* System driver to accrue an offset. A positive argument means slew
+   the clock forwards.  The suggested correction rate of time to correct the
+   offset is given in 'corr_rate'. */
+typedef void (*lcl_AccrueOffsetDriver)(double offset, double corr_rate);
+
+/* System driver to apply a step offset. A positive argument means step
+   the clock forwards. */
+typedef int (*lcl_ApplyStepOffsetDriver)(double offset);
+
+/* System driver to convert a raw time to an adjusted (cooked) time.
+   The number of seconds returned in 'corr' have to be added to the
+   raw time to get the corrected time */
+typedef void (*lcl_OffsetCorrectionDriver)(struct timespec *raw, double *corr, double *err);
+
+/* System driver to schedule leap seconds and set TAI-UTC offset */
+typedef void (*lcl_SetLeapDriver)(int leap, int tai_offset);
+
+/* System driver to set the synchronisation status */
+typedef void (*lcl_SetSyncStatusDriver)(int synchronised, double est_error, double max_error);
+
+extern void lcl_InvokeDispersionNotifyHandlers(double dispersion);
+
+extern void
+lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
+                          lcl_SetFrequencyDriver set_freq,
+                          lcl_AccrueOffsetDriver accrue_offset,
+                          lcl_ApplyStepOffsetDriver apply_step_offset,
+                          lcl_OffsetCorrectionDriver offset_convert,
+                          lcl_SetLeapDriver set_leap,
+                          lcl_SetSyncStatusDriver set_sync_status);
+
+#endif /* GOT_LOCALP_H */
diff --git a/chrony_3_3/logging.c b/chrony_3_3/logging.c
new file mode 100644
index 0000000..7d9dbb8
--- /dev/null
+++ b/chrony_3_3/logging.c
@@ -0,0 +1,321 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2011-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Module to handle logging of diagnostic information
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "conf.h"
+#include "logging.h"
+#include "util.h"
+
+/* This is used by DEBUG_LOG macro */
+int log_debug_enabled = 0;
+
+/* ================================================== */
+/* Flag indicating we have initialised */
+static int initialised = 0;
+
+static FILE *file_log;
+static int system_log = 0;
+
+static int parent_fd = 0;
+
+#define DEBUG_LEVEL_PRINT_FUNCTION 2
+#define DEBUG_LEVEL_PRINT_DEBUG 2
+static int debug_level = 0;
+
+struct LogFile {
+  const char *name;
+  const char *banner;
+  FILE *file;
+  unsigned long writes;
+};
+
+static int n_filelogs = 0;
+
+/* Increase this when adding a new logfile */
+#define MAX_FILELOGS 6
+
+static struct LogFile logfiles[MAX_FILELOGS];
+
+/* ================================================== */
+/* Init function */
+
+void
+LOG_Initialise(void)
+{
+  initialised = 1;
+  file_log = stderr;
+}
+
+/* ================================================== */
+/* Fini function */
+
+void
+LOG_Finalise(void)
+{
+  if (system_log)
+    closelog();
+
+  if (file_log)
+    fclose(file_log);
+
+  LOG_CycleLogFiles();
+
+  initialised = 0;
+}
+
+/* ================================================== */
+
+static void log_message(int fatal, LOG_Severity severity, const char *message)
+{
+  if (system_log) {
+    int priority;
+    switch (severity) {
+      case LOGS_DEBUG:
+        priority = LOG_DEBUG;
+        break;
+      case LOGS_INFO:
+        priority = LOG_INFO;
+        break;
+      case LOGS_WARN:
+        priority = LOG_WARNING;
+        break;
+      case LOGS_ERR:
+        priority = LOG_ERR;
+        break;
+      case LOGS_FATAL:
+        priority = LOG_CRIT;
+        break;
+      default:
+        assert(0);
+    }
+    syslog(priority, fatal ? "Fatal error : %s" : "%s", message);
+  } else if (file_log) {
+    fprintf(file_log, fatal ? "Fatal error : %s\n" : "%s\n", message);
+  }
+}
+
+/* ================================================== */
+
+void LOG_Message(LOG_Severity severity,
+#if DEBUG > 0
+                 int line_number, const char *filename, const char *function_name,
+#endif
+                 const char *format, ...)
+{
+  char buf[2048];
+  va_list other_args;
+  time_t t;
+  struct tm stm;
+
+  if (!system_log && file_log) {
+    /* Don't clutter up syslog with timestamps and internal debugging info */
+    time(&t);
+    stm = *gmtime(&t);
+    strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &stm);
+    fprintf(file_log, "%s ", buf);
+#if DEBUG > 0
+    if (debug_level >= DEBUG_LEVEL_PRINT_FUNCTION)
+      fprintf(file_log, "%s:%d:(%s) ", filename, line_number, function_name);
+#endif
+  }
+
+  va_start(other_args, format);
+  vsnprintf(buf, sizeof(buf), format, other_args);
+  va_end(other_args);
+
+  switch (severity) {
+    case LOGS_DEBUG:
+    case LOGS_INFO:
+    case LOGS_WARN:
+    case LOGS_ERR:
+      log_message(0, severity, buf);
+      break;
+    case LOGS_FATAL:
+      log_message(1, severity, buf);
+
+      /* Send the message also to the foreground process if it is
+         still running, or stderr if it is still open */
+      if (parent_fd > 0) {
+        if (write(parent_fd, buf, strlen(buf) + 1) < 0)
+          ; /* Not much we can do here */
+      } else if (system_log && parent_fd == 0) {
+        system_log = 0;
+        log_message(1, severity, buf);
+      }
+      break;
+    default:
+      assert(0);
+  }
+}
+
+/* ================================================== */
+
+void
+LOG_OpenFileLog(const char *log_file)
+{
+  FILE *f;
+
+  f = fopen(log_file, "a");
+  if (!f)
+    LOG_FATAL("Could not open log file %s", log_file);
+
+  /* Enable line buffering */
+  setvbuf(f, NULL, _IOLBF, BUFSIZ);
+
+  file_log = f;
+}
+
+
+/* ================================================== */
+
+void
+LOG_OpenSystemLog(void)
+{
+  system_log = 1;
+  openlog("chronyd", LOG_PID, LOG_DAEMON);
+}
+
+/* ================================================== */
+
+void LOG_SetDebugLevel(int level)
+{
+  debug_level = level;
+  if (level >= DEBUG_LEVEL_PRINT_DEBUG) {
+    log_debug_enabled = 1;
+  }
+}
+
+/* ================================================== */
+
+void
+LOG_SetParentFd(int fd)
+{
+  parent_fd = fd;
+  if (file_log == stderr)
+    file_log = NULL;
+}
+
+/* ================================================== */
+
+void
+LOG_CloseParentFd()
+{
+  if (parent_fd > 0)
+    close(parent_fd);
+  parent_fd = -1;
+}
+
+/* ================================================== */
+
+LOG_FileID
+LOG_FileOpen(const char *name, const char *banner)
+{
+  assert(n_filelogs < MAX_FILELOGS);
+
+  logfiles[n_filelogs].name = name;
+  logfiles[n_filelogs].banner = banner;
+  logfiles[n_filelogs].file = NULL;
+  logfiles[n_filelogs].writes = 0;
+
+  return n_filelogs++;
+}
+
+/* ================================================== */
+
+void
+LOG_FileWrite(LOG_FileID id, const char *format, ...)
+{
+  va_list other_args;
+  int banner;
+
+  if (id < 0 || id >= n_filelogs || !logfiles[id].name)
+    return;
+
+  if (!logfiles[id].file) {
+    char filename[512], *logdir = CNF_GetLogDir();
+
+    if (logdir[0] == '\0') {
+      LOG(LOGS_WARN, "logdir not specified");
+      logfiles[id].name = NULL;
+      return;
+    }
+
+    if (snprintf(filename, sizeof(filename), "%s/%s.log",
+                 logdir, logfiles[id].name) >= sizeof (filename) ||
+        !(logfiles[id].file = fopen(filename, "a"))) {
+      LOG(LOGS_WARN, "Could not open log file %s", filename);
+      logfiles[id].name = NULL;
+      return;
+    }
+
+    /* Close on exec */
+    UTI_FdSetCloexec(fileno(logfiles[id].file));
+  }
+
+  banner = CNF_GetLogBanner();
+  if (banner && logfiles[id].writes++ % banner == 0) {
+    char bannerline[256];
+    int i, bannerlen;
+
+    bannerlen = strlen(logfiles[id].banner);
+
+    for (i = 0; i < bannerlen; i++)
+      bannerline[i] = '=';
+    bannerline[i] = '\0';
+
+    fprintf(logfiles[id].file, "%s\n", bannerline);
+    fprintf(logfiles[id].file, "%s\n", logfiles[id].banner);
+    fprintf(logfiles[id].file, "%s\n", bannerline);
+  }
+
+  va_start(other_args, format);
+  vfprintf(logfiles[id].file, format, other_args);
+  va_end(other_args);
+  fprintf(logfiles[id].file, "\n");
+
+  fflush(logfiles[id].file);
+}
+
+/* ================================================== */
+
+void
+LOG_CycleLogFiles(void)
+{
+  LOG_FileID i;
+
+  for (i = 0; i < n_filelogs; i++) {
+    if (logfiles[i].file)
+      fclose(logfiles[i].file);
+    logfiles[i].file = NULL;
+    logfiles[i].writes = 0;
+  }
+}
+
+/* ================================================== */
diff --git a/chrony_3_3/logging.h b/chrony_3_3/logging.h
new file mode 100644
index 0000000..5bb46f5
--- /dev/null
+++ b/chrony_3_3/logging.h
@@ -0,0 +1,125 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2002
+ * Copyright (C) Miroslav Lichvar  2013-2015
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * 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 diagnostic logging module
+
+  */
+
+#ifndef GOT_LOGGING_H
+#define GOT_LOGGING_H
+
+#include "sysincl.h"
+
+/* Flag indicating whether debug messages are logged */
+extern int log_debug_enabled;
+
+/* Line logging macros.  If the compiler is GNU C, we take advantage of
+   being able to get the function name also. */
+
+#ifdef __GNUC__
+#define FUNCTION_NAME __FUNCTION__
+#define FORMAT_ATTRIBUTE_PRINTF(str, first) __attribute__ ((format (printf, str, first)))
+#else
+#define FUNCTION_NAME ""
+#define FORMAT_ATTRIBUTE_PRINTF(str, first)
+#endif
+
+#if DEBUG > 0
+#define LOG_MESSAGE(severity, ...) \
+  LOG_Message(severity, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
+#else
+#define LOG_MESSAGE(severity, ...) \
+  LOG_Message(severity, __VA_ARGS__)
+#endif
+
+#define DEBUG_LOG(...) \
+  do { \
+    if (DEBUG && log_debug_enabled) \
+      LOG_MESSAGE(LOGS_DEBUG, __VA_ARGS__); \
+  } while (0)
+
+#define LOG_FATAL(...) \
+  do { \
+    LOG_MESSAGE(LOGS_FATAL, __VA_ARGS__); \
+    exit(1); \
+  } while (0)
+
+#define LOG(severity, ...) LOG_MESSAGE(severity, __VA_ARGS__)
+
+/* Definition of severity */
+typedef enum {
+  LOGS_INFO,
+  LOGS_WARN,
+  LOGS_ERR,
+  LOGS_FATAL,
+  LOGS_DEBUG
+} LOG_Severity;
+
+/* Init function */
+extern void LOG_Initialise(void);
+
+/* Fini function */
+extern void LOG_Finalise(void);
+
+/* Line logging function */
+#if DEBUG > 0
+FORMAT_ATTRIBUTE_PRINTF(5, 6)
+extern void LOG_Message(LOG_Severity severity, int line_number, const char *filename,
+                        const char *function_name, const char *format, ...);
+#else
+FORMAT_ATTRIBUTE_PRINTF(2, 3)
+extern void LOG_Message(LOG_Severity severity, const char *format, ...);
+#endif
+
+/* Set debug level:
+   0, 1 - only non-debug messages are logged
+   2    - debug messages are logged too, all messages are prefixed with
+          filename, line, and function name
+   */
+extern void LOG_SetDebugLevel(int level);
+
+/* Log messages to a file instead of stderr */
+extern void LOG_OpenFileLog(const char *log_file);
+
+/* Log messages to syslog instead of stderr */
+extern void LOG_OpenSystemLog(void);
+
+/* Stop using stderr and send fatal message to the foreground process */
+extern void LOG_SetParentFd(int fd);
+
+/* Close the pipe to the foreground process so it can exit */
+extern void LOG_CloseParentFd(void);
+
+/* File logging functions */
+
+typedef int LOG_FileID;
+
+extern LOG_FileID LOG_FileOpen(const char *name, const char *banner);
+
+FORMAT_ATTRIBUTE_PRINTF(2, 3)
+extern void LOG_FileWrite(LOG_FileID id, const char *format, ...);
+
+extern void LOG_CycleLogFiles(void);
+
+#endif /* GOT_LOGGING_H */
diff --git a/chrony_3_3/main.c b/chrony_3_3/main.c
new file mode 100644
index 0000000..a2202e9
--- /dev/null
+++ b/chrony_3_3/main.c
@@ -0,0 +1,623 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) John G. Hasler  2009
+ * Copyright (C) Miroslav Lichvar  2012-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  The main program
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "main.h"
+#include "sched.h"
+#include "local.h"
+#include "sys.h"
+#include "ntp_io.h"
+#include "ntp_signd.h"
+#include "ntp_sources.h"
+#include "ntp_core.h"
+#include "sources.h"
+#include "sourcestats.h"
+#include "reference.h"
+#include "logging.h"
+#include "conf.h"
+#include "cmdmon.h"
+#include "keys.h"
+#include "manual.h"
+#include "rtc.h"
+#include "refclock.h"
+#include "clientlog.h"
+#include "nameserv.h"
+#include "privops.h"
+#include "smooth.h"
+#include "tempcomp.h"
+#include "util.h"
+
+/* ================================================== */
+
+/* Set when the initialisation chain has been completed.  Prevents finalisation
+ * chain being run if a fatal error happened early. */
+
+static int initialised = 0;
+
+static int exit_status = 0;
+
+static int reload = 0;
+
+static REF_Mode ref_mode = REF_ModeNormal;
+
+/* ================================================== */
+
+static void
+do_platform_checks(void)
+{
+  /* Require at least 32-bit integers, two's complement representation and
+     the usual implementation of conversion of unsigned integers */
+  assert(sizeof (int) >= 4);
+  assert(-1 == ~0);
+  assert((int32_t)4294967295U == (int32_t)-1);
+}
+
+/* ================================================== */
+
+static void
+delete_pidfile(void)
+{
+  const char *pidfile = CNF_GetPidFile();
+
+  if (!pidfile[0])
+    return;
+
+  /* Don't care if this fails, there's not a lot we can do */
+  unlink(pidfile);
+}
+
+/* ================================================== */
+
+void
+MAI_CleanupAndExit(void)
+{
+  if (!initialised) exit(exit_status);
+  
+  if (CNF_GetDumpDir()[0] != '\0') {
+    SRC_DumpSources();
+  }
+
+  /* Don't update clock when removing sources */
+  REF_SetMode(REF_ModeIgnore);
+
+  SMT_Finalise();
+  TMC_Finalise();
+  MNL_Finalise();
+  CLG_Finalise();
+  NSD_Finalise();
+  NSR_Finalise();
+  SST_Finalise();
+  NCR_Finalise();
+  NIO_Finalise();
+  CAM_Finalise();
+  KEY_Finalise();
+  RCL_Finalise();
+  SRC_Finalise();
+  REF_Finalise();
+  RTC_Finalise();
+  SYS_Finalise();
+  SCH_Finalise();
+  LCL_Finalise();
+  PRV_Finalise();
+
+  delete_pidfile();
+  
+  CNF_Finalise();
+  HSH_Finalise();
+  LOG_Finalise();
+
+  exit(exit_status);
+}
+
+/* ================================================== */
+
+static void
+signal_cleanup(int x)
+{
+  if (!initialised) exit(0);
+  SCH_QuitProgram();
+}
+
+/* ================================================== */
+
+static void
+quit_timeout(void *arg)
+{
+  /* Return with non-zero status if the clock is not synchronised */
+  exit_status = REF_GetOurStratum() >= NTP_MAX_STRATUM;
+  SCH_QuitProgram();
+}
+
+/* ================================================== */
+
+static void
+ntp_source_resolving_end(void)
+{
+  NSR_SetSourceResolvingEndHandler(NULL);
+
+  if (reload) {
+    /* Note, we want reload to come well after the initialisation from
+       the real time clock - this gives us a fighting chance that the
+       system-clock scale for the reloaded samples still has a
+       semblence of validity about it. */
+    SRC_ReloadSources();
+  }
+
+  SRC_RemoveDumpFiles();
+  RTC_StartMeasurements();
+  RCL_StartRefclocks();
+  NSR_StartSources();
+  NSR_AutoStartSources();
+
+  /* Special modes can end only when sources update their reachability.
+     Give up immediatelly if there are no active sources. */
+  if (ref_mode != REF_ModeNormal && !SRC_ActiveSources()) {
+    REF_SetUnsynchronised();
+  }
+}
+
+/* ================================================== */
+
+static void
+post_init_ntp_hook(void *anything)
+{
+  if (ref_mode == REF_ModeInitStepSlew) {
+    /* Remove the initstepslew sources and set normal mode */
+    NSR_RemoveAllSources();
+    ref_mode = REF_ModeNormal;
+    REF_SetMode(ref_mode);
+  }
+
+  /* Close the pipe to the foreground process so it can exit */
+  LOG_CloseParentFd();
+
+  CNF_AddSources();
+  CNF_AddBroadcasts();
+
+  NSR_SetSourceResolvingEndHandler(ntp_source_resolving_end);
+  NSR_ResolveSources();
+}
+
+/* ================================================== */
+
+static void
+reference_mode_end(int result)
+{
+  switch (ref_mode) {
+    case REF_ModeNormal:
+    case REF_ModeUpdateOnce:
+    case REF_ModePrintOnce:
+      exit_status = !result;
+      SCH_QuitProgram();
+      break;
+    case REF_ModeInitStepSlew:
+      /* Switch to the normal mode, the delay is used to prevent polling
+         interval shorter than the burst interval if some configured servers
+         were used also for initstepslew */
+      SCH_AddTimeoutByDelay(2.0, post_init_ntp_hook, NULL);
+      break;
+    default:
+      assert(0);
+  }
+}
+
+/* ================================================== */
+
+static void
+post_init_rtc_hook(void *anything)
+{
+  if (CNF_GetInitSources() > 0) {
+    CNF_AddInitSources();
+    NSR_StartSources();
+    assert(REF_GetMode() != REF_ModeNormal);
+    /* Wait for mode end notification */
+  } else {
+    (post_init_ntp_hook)(NULL);
+  }
+}
+
+/* ================================================== */
+
+static void
+check_pidfile(void)
+{
+  const char *pidfile = CNF_GetPidFile();
+  FILE *in;
+  int pid, count;
+  
+  in = fopen(pidfile, "r");
+  if (!in)
+    return;
+
+  count = fscanf(in, "%d", &pid);
+  fclose(in);
+  
+  if (count != 1)
+    return;
+
+  if (getsid(pid) < 0)
+    return;
+
+  LOG_FATAL("Another chronyd may already be running (pid=%d), check %s",
+            pid, pidfile);
+}
+
+/* ================================================== */
+
+static void
+write_pidfile(void)
+{
+  const char *pidfile = CNF_GetPidFile();
+  FILE *out;
+
+  if (!pidfile[0])
+    return;
+
+  out = fopen(pidfile, "w");
+  if (!out) {
+    LOG_FATAL("Could not open %s : %s", pidfile, strerror(errno));
+  } else {
+    fprintf(out, "%d\n", (int)getpid());
+    fclose(out);
+  }
+}
+
+/* ================================================== */
+
+#define DEV_NULL "/dev/null"
+
+static void
+go_daemon(void)
+{
+  int pid, fd, pipefd[2];
+
+  /* Create pipe which will the daemon use to notify the grandparent
+     when it's initialised or send an error message */
+  if (pipe(pipefd)) {
+    LOG_FATAL("pipe() failed : %s", strerror(errno));
+  }
+
+  /* Does this preserve existing signal handlers? */
+  pid = fork();
+
+  if (pid < 0) {
+    LOG_FATAL("fork() failed : %s", strerror(errno));
+  } else if (pid > 0) {
+    /* In the 'grandparent' */
+    char message[1024];
+    int r;
+
+    close(pipefd[1]);
+    r = read(pipefd[0], message, sizeof (message));
+    if (r) {
+      if (r > 0) {
+        /* Print the error message from the child */
+        message[sizeof (message) - 1] = '\0';
+        fprintf(stderr, "%s\n", message);
+      }
+      exit(1);
+    } else
+      exit(0);
+  } else {
+    close(pipefd[0]);
+
+    setsid();
+
+    /* Do 2nd fork, as-per recommended practice for launching daemons. */
+    pid = fork();
+
+    if (pid < 0) {
+      LOG_FATAL("fork() failed : %s", strerror(errno));
+    } else if (pid > 0) {
+      exit(0); /* In the 'parent' */
+    } else {
+      /* In the child we want to leave running as the daemon */
+
+      /* Change current directory to / */
+      if (chdir("/") < 0) {
+        LOG_FATAL("chdir() failed : %s", strerror(errno));
+      }
+
+      /* Don't keep stdin/out/err from before. But don't close
+         the parent pipe yet. */
+      for (fd=0; fd<1024; fd++) {
+        if (fd != pipefd[1])
+          close(fd);
+      }
+
+      LOG_SetParentFd(pipefd[1]);
+
+      /* Open /dev/null as new stdin/out/err */
+      errno = 0;
+      if (open(DEV_NULL, O_RDONLY) != STDIN_FILENO ||
+          open(DEV_NULL, O_WRONLY) != STDOUT_FILENO ||
+          open(DEV_NULL, O_RDWR) != STDERR_FILENO)
+        LOG_FATAL("Could not open %s : %s", DEV_NULL, strerror(errno));
+    }
+  }
+}
+
+/* ================================================== */
+
+static void
+print_help(const char *progname)
+{
+      printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-t TIMEOUT] [-f FILE|COMMAND...]\n",
+             progname);
+}
+
+/* ================================================== */
+
+static void
+print_version(void)
+{
+  printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
+}
+
+/* ================================================== */
+
+static int
+parse_int_arg(const char *arg)
+{
+  int i;
+
+  if (sscanf(arg, "%d", &i) != 1)
+    LOG_FATAL("Invalid argument %s", arg);
+  return i;
+}
+
+/* ================================================== */
+
+int main
+(int argc, char **argv)
+{
+  const char *conf_file = DEFAULT_CONF_FILE;
+  const char *progname = argv[0];
+  char *user = NULL, *log_file = NULL;
+  struct passwd *pw;
+  int opt, debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
+  int do_init_rtc = 0, restarted = 0, client_only = 0, timeout = 0;
+  int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
+  int clock_control = 1, system_log = 1;
+  int config_args = 0;
+
+  do_platform_checks();
+
+  LOG_Initialise();
+
+  /* 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, "46df:F:hl:mnP:qQrRst:u:vx")) != -1) {
+    switch (opt) {
+      case '4':
+      case '6':
+        address_family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6;
+        break;
+      case 'd':
+        debug++;
+        nofork = 1;
+        system_log = 0;
+        break;
+      case 'f':
+        conf_file = optarg;
+        break;
+      case 'F':
+        scfilter_level = parse_int_arg(optarg);
+        break;
+      case 'l':
+        log_file = optarg;
+        break;
+      case 'm':
+        lock_memory = 1;
+        break;
+      case 'n':
+        nofork = 1;
+        break;
+      case 'P':
+        sched_priority = parse_int_arg(optarg);
+        break;
+      case 'q':
+        ref_mode = REF_ModeUpdateOnce;
+        nofork = 1;
+        client_only = 0;
+        system_log = 0;
+        break;
+      case 'Q':
+        ref_mode = REF_ModePrintOnce;
+        nofork = 1;
+        client_only = 1;
+        clock_control = 0;
+        system_log = 0;
+        break;
+      case 'r':
+        reload = 1;
+        break;
+      case 'R':
+        restarted = 1;
+        break;
+      case 's':
+        do_init_rtc = 1;
+        break;
+      case 't':
+        timeout = parse_int_arg(optarg);
+        break;
+      case 'u':
+        user = optarg;
+        break;
+      case 'v':
+        print_version();
+        return 0;
+      case 'x':
+        clock_control = 0;
+        break;
+      default:
+        print_help(progname);
+        return opt != 'h';
+    }
+  }
+
+  if (getuid() && !client_only)
+    LOG_FATAL("Not superuser");
+
+  /* Turn into a daemon */
+  if (!nofork) {
+    go_daemon();
+  }
+
+  if (log_file) {
+    LOG_OpenFileLog(log_file);
+  } else if (system_log) {
+    LOG_OpenSystemLog();
+  }
+  
+  LOG_SetDebugLevel(debug);
+  
+  LOG(LOGS_INFO, "chronyd version %s starting (%s)", CHRONY_VERSION, CHRONYD_FEATURES);
+
+  DNS_SetAddressFamily(address_family);
+
+  CNF_Initialise(restarted, client_only);
+
+  /* Parse the config file or the remaining command line arguments */
+  config_args = argc - optind;
+  if (!config_args) {
+    CNF_ReadFile(conf_file);
+  } else {
+    for (; optind < argc; optind++)
+      CNF_ParseLine(NULL, config_args + optind - argc + 1, argv[optind]);
+  }
+
+  /* Check whether another chronyd may already be running */
+  check_pidfile();
+
+  /* Write our pidfile to prevent other chronyds running */
+  write_pidfile();
+
+  if (!user)
+    user = CNF_GetUser();
+
+  pw = getpwnam(user);
+  if (!pw)
+    LOG_FATAL("Could not get user/group ID of %s", user);
+
+  /* Create directories for sockets, log files, and dump files */
+  CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
+
+  PRV_Initialise();
+  LCL_Initialise();
+  SCH_Initialise();
+  SYS_Initialise(clock_control);
+  RTC_Initialise(do_init_rtc);
+  SRC_Initialise();
+  RCL_Initialise();
+  KEY_Initialise();
+
+  /* Open privileged ports before dropping root */
+  CAM_Initialise(address_family);
+  NIO_Initialise(address_family);
+  NCR_Initialise();
+  CNF_SetupAccessRestrictions();
+
+  /* Command-line switch must have priority */
+  if (!sched_priority) {
+    sched_priority = CNF_GetSchedPriority();
+  }
+  if (sched_priority) {
+    SYS_SetScheduler(sched_priority);
+  }
+
+  if (lock_memory || CNF_GetLockMemory()) {
+    SYS_LockMemory();
+  }
+
+  /* Drop root privileges if the specified user has a non-zero UID */
+  if (!geteuid() && (pw->pw_uid || pw->pw_gid))
+    SYS_DropRoot(pw->pw_uid, pw->pw_gid);
+
+  REF_Initialise();
+  SST_Initialise();
+  NSR_Initialise();
+  NSD_Initialise();
+  CLG_Initialise();
+  MNL_Initialise();
+  TMC_Initialise();
+  SMT_Initialise();
+
+  /* From now on, it is safe to do finalisation on exit */
+  initialised = 1;
+
+  UTI_SetQuitSignalsHandler(signal_cleanup);
+
+  CAM_OpenUnixSocket();
+
+  if (scfilter_level)
+    SYS_EnableSystemCallFilter(scfilter_level);
+
+  if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) {
+    ref_mode = REF_ModeInitStepSlew;
+  }
+
+  REF_SetModeEndHandler(reference_mode_end);
+  REF_SetMode(ref_mode);
+
+  if (timeout > 0)
+    SCH_AddTimeoutByDelay(timeout, quit_timeout, NULL);
+
+  if (do_init_rtc) {
+    RTC_TimeInit(post_init_rtc_hook, NULL);
+  } else {
+    post_init_rtc_hook(NULL);
+  }
+
+  /* The program normally runs under control of the main loop in
+     the scheduler. */
+  SCH_MainLoop();
+
+  LOG(LOGS_INFO, "chronyd exiting");
+
+  MAI_CleanupAndExit();
+
+  return 0;
+}
+
+/* ================================================== */
diff --git a/chrony_3_3/main.h b/chrony_3_3/main.h
new file mode 100644
index 0000000..d6d502a
--- /dev/null
+++ b/chrony_3_3/main.h
@@ -0,0 +1,35 @@
+/*
+  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 main routine
+  */
+
+#ifndef GOT_MAIN_H
+#define GOT_MAIN_H
+
+/* Function to clean up at end of run */
+extern void MAI_CleanupAndExit(void);
+
+#endif /* GOT_MAIN_H */
+
+
diff --git a/chrony_3_3/manual.c b/chrony_3_3/manual.c
new file mode 100644
index 0000000..bf52d14
--- /dev/null
+++ b/chrony_3_3/manual.c
@@ -0,0 +1,331 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Routines for implementing manual input of real time.
+
+  The daemon accepts manual time input over the control connection,
+  and adjusts the system time to match.  Besides this, though, it can
+  determine the average rate of time loss or gain of the local system
+  and adjust the frequency accordingly.
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "manual.h"
+#include "logging.h"
+#include "local.h"
+#include "conf.h"
+#include "util.h"
+#include "ntp.h"
+#include "reference.h"
+#include "regress.h"
+
+static int enabled = 0;
+
+/* More recent samples at highest indices */
+typedef struct {
+  struct timespec when; /* This is our 'cooked' time */
+  double orig_offset; /*+ Not modified by slew samples */
+  double offset; /*+ if we are fast of the supplied reference */
+  double residual; /*+ regression residual (sign convention given by
+                     (measured-predicted)) */
+} Sample;
+
+#define MIN_SAMPLE_SEPARATION 1.0
+
+#define MAX_SAMPLES 16
+
+static Sample samples[16];
+static int n_samples;
+
+/* ================================================== */
+
+static void
+slew_samples(struct timespec *raw,
+             struct timespec *cooked,
+             double dfreq,
+             double doffset,
+             LCL_ChangeType change_type,
+             void *not_used);
+
+/* ================================================== */
+
+void
+MNL_Initialise(void)
+{
+  if (CNF_GetManualEnabled()) {
+    enabled = 1;
+  } else {
+    enabled = 0;
+  }
+
+  n_samples = 0;
+
+  LCL_AddParameterChangeHandler(slew_samples, NULL);
+}
+
+/* ================================================== */
+
+void
+MNL_Finalise(void)
+{
+}
+
+/* ================================================== */
+
+static void
+estimate_and_set_system(struct timespec *now, int offset_provided, double offset,
+                        double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm)
+{
+  double agos[MAX_SAMPLES], offsets[MAX_SAMPLES];
+  double b0, b1;
+  int n_runs, best_start; /* Unused results from regression analyser */
+  int i;
+  double freq = 0.0;
+  double skew = 0.099999999; /* All 9's when printed to log file */
+  int found_freq;
+  double slew_by;
+
+  b0 = offset_provided ? offset : 0.0;
+  b1 = freq = 0.0;
+  found_freq = 0;
+
+  if (n_samples > 1) {
+    for (i=0; i<n_samples; i++) {
+      agos[i] = UTI_DiffTimespecsToDouble(&samples[n_samples - 1].when, &samples[i].when);
+      offsets[i] = samples[i].offset;
+    }
+    
+    if (RGR_FindBestRobustRegression(agos, offsets, n_samples, 1.0e-8,
+                                     &b0, &b1, &n_runs, &best_start)) {
+      /* Ignore b0 from regression; treat offset as being the most
+         recently entered value.  (If the administrator knows he's put
+         an outlier in, he will rerun the settime operation.)   However,
+         the frequency estimate comes from the regression. */
+      freq = -b1;
+      found_freq = 1;
+    }
+  } else {
+    agos[0] = 0.0;
+    offsets[0] = b0;
+  }
+
+  if (offset_provided) {
+    slew_by = offset;
+  } else {
+    slew_by = b0;
+  }
+  
+  if (found_freq) {
+    LOG(LOGS_INFO, "Making a frequency change of %.3f ppm and a slew of %.6f",
+        1.0e6 * freq, slew_by);
+    
+    REF_SetManualReference(now,
+                           slew_by,
+                           freq, skew);
+  } else {
+    LOG(LOGS_INFO, "Making a slew of %.6f", slew_by);
+    REF_SetManualReference(now,
+                           slew_by,
+                           0.0, skew);
+  }
+  
+  if (reg_offset) *reg_offset = b0;
+  if (dfreq_ppm) *dfreq_ppm = 1.0e6 * freq;
+  if (new_afreq_ppm) *new_afreq_ppm = LCL_ReadAbsoluteFrequency();
+  
+  /* Calculate residuals to store them */
+  for (i=0; i<n_samples; i++) {
+    samples[i].residual = offsets[i] - (b0 + agos[i] * b1);
+  }
+  
+}
+
+/* ================================================== */
+
+int
+MNL_AcceptTimestamp(struct timespec *ts, double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm)
+{
+  struct timespec now;
+  double offset, diff;
+  int i;
+
+  if (enabled) {
+    LCL_ReadCookedTime(&now, NULL);
+
+    /* Make sure the provided timestamp is sane and the sample
+       is not too close to the last one */
+
+    if (!UTI_IsTimeOffsetSane(ts, 0.0))
+     return 0;
+
+    if (n_samples) {
+      diff = UTI_DiffTimespecsToDouble(&now, &samples[n_samples - 1].when);
+      if (diff < MIN_SAMPLE_SEPARATION)
+        return 0;
+    }
+
+    offset = UTI_DiffTimespecsToDouble(&now, ts);
+
+    /* Check if buffer full up */
+    if (n_samples == MAX_SAMPLES) {
+      /* Shift samples down */
+      for (i=1; i<n_samples; i++) {
+        samples[i-1] = samples[i];
+      }
+      --n_samples;
+    }
+    
+    samples[n_samples].when = now;
+    samples[n_samples].offset = offset;
+    samples[n_samples].orig_offset = offset;
+    ++n_samples;
+
+    estimate_and_set_system(&now, 1, offset, reg_offset, dfreq_ppm, new_afreq_ppm);
+
+    return 1;
+
+  } else {
+  
+    return 0;
+
+  }
+}
+
+/* ================================================== */
+
+static void
+slew_samples(struct timespec *raw,
+             struct timespec *cooked,
+             double dfreq,
+             double doffset,
+             LCL_ChangeType change_type,
+             void *not_used)
+{
+  double delta_time;
+  int i;
+
+  if (change_type == LCL_ChangeUnknownStep) {
+    MNL_Reset();
+  }
+
+  for (i=0; i<n_samples; i++) {
+    UTI_AdjustTimespec(&samples[i].when, cooked, &samples[i].when, &delta_time,
+        dfreq, doffset);
+    samples[i].offset += delta_time;
+  }
+}
+
+/* ================================================== */
+
+void
+MNL_Enable(void)
+{
+  enabled = 1;
+}
+
+
+/* ================================================== */
+
+void
+MNL_Disable(void)
+{
+  enabled = 0;
+}
+
+/* ================================================== */
+
+void
+MNL_Reset(void)
+{
+  n_samples = 0;
+}
+
+/* ================================================== */
+
+int
+MNL_IsEnabled(void)
+{
+  return enabled;
+}
+
+/* ================================================== */
+/* Generate report data for the REQ_MANUAL_LIST command/monitoring
+   protocol */
+
+void
+MNL_ReportSamples(RPT_ManualSamplesReport *report, int max, int *n)
+{
+  int i;
+
+  if (n_samples > max) {
+    *n = max;
+  } else {
+    *n = n_samples;
+  }
+
+  for (i=0; i<n_samples && i<max; i++) {
+    report[i].when = samples[i].when;
+    report[i].slewed_offset = samples[i].offset;
+    report[i].orig_offset = samples[i].orig_offset;
+    report[i].residual = samples[i].residual;
+  }
+}
+
+/* ================================================== */
+/* Delete a sample if it's within range, re-estimate the error and
+   drift and apply it to the system clock. */
+
+int
+MNL_DeleteSample(int index)
+{
+  int i;
+  struct timespec now;
+
+  if ((index < 0) || (index >= n_samples)) {
+    return 0;
+  }
+
+  /* Crunch the samples down onto the one being deleted */
+
+  for (i=index; i<(n_samples-1); i++) {
+    samples[i] = samples[i+1];
+  }
+  
+  n_samples -= 1;
+
+  /* Now re-estimate.  NULLs because we don't want the parameters back
+     in this case. */
+  LCL_ReadCookedTime(&now, NULL);
+  estimate_and_set_system(&now, 0, 0.0, NULL, NULL, NULL);
+
+  return 1;
+
+}
+
+/* ================================================== */
+
+
diff --git a/chrony_3_3/manual.h b/chrony_3_3/manual.h
new file mode 100644
index 0000000..7f3d0b2
--- /dev/null
+++ b/chrony_3_3/manual.h
@@ -0,0 +1,46 @@
+/*
+  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 manual time input module.
+
+  */
+
+#ifndef GOT_MANUAL_H
+#define GOT_MANUAL_H
+
+#include "sysincl.h"
+#include "reports.h"
+
+extern void MNL_Initialise(void);
+extern void MNL_Finalise(void);
+extern int MNL_AcceptTimestamp(struct timespec *ts, double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm);
+
+extern void MNL_Enable(void);
+extern void MNL_Disable(void);
+extern void MNL_Reset(void);
+extern int MNL_IsEnabled(void);
+
+extern void MNL_ReportSamples(RPT_ManualSamplesReport *report, int max, int *n);
+extern int MNL_DeleteSample(int index);
+
+#endif /* GOT_MANUAL_H */
diff --git a/chrony_3_3/md5.c b/chrony_3_3/md5.c
new file mode 100644
index 0000000..f997a6e
--- /dev/null
+++ b/chrony_3_3/md5.c
@@ -0,0 +1,322 @@
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines                         **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version                   **
+ ** Revised (for MD5): RLR 4/27/91                                    **
+ **   -- G modified to have y&~z instead of y&z                       **
+ **   -- FF, GG, HH modified to add in last register done             **
+ **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     **
+ **   -- distinct additive constant for each step                     **
+ **   -- round 4 added, working mod 7                                 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#include "md5.h"
+
+/*
+ ***********************************************************************
+ **  Message-digest routines:                                         **
+ **  To form the message digest for a message M                       **
+ **    (1) Initialize a context buffer mdContext using MD5Init        **
+ **    (2) Call MD5Update on mdContext and M                          **
+ **    (3) Call MD5Final on mdContext                                 **
+ **  The message digest is now in mdContext->digest[0...15]           **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform (UINT4 *, UINT4 *);
+
+#ifdef	__STDC__
+static const
+#else
+static
+#endif
+unsigned char PADDING[64] = {
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#if	defined(FAST_MD5) && defined(__GNUC__) && defined(mc68000)
+/*
+ * If we're on a 68000 based CPU and using a GNU C compiler with
+ * inline assembly code, we can speed this up a bit.
+ */
+inline UINT4 ROTATE_LEFT(UINT4 x, int n)
+{   
+    asm("roll %2,%0" : "=d" (x) : "0" (x), "Ir" (n));
+    return x;
+}
+#else
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+#endif
+
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+  {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) \
+  {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) \
+  {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) \
+  {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+
+/* The routine MD5Init initializes the message-digest context
+   mdContext. All fields are set to zero.
+ */
+void MD5Init (mdContext)
+MD5_CTX *mdContext;
+{
+  mdContext->i[0] = mdContext->i[1] = (UINT4)0;
+
+  /* Load magic initialization constants.
+   */
+  mdContext->buf[0] = (UINT4)0x67452301;
+  mdContext->buf[1] = (UINT4)0xefcdab89;
+  mdContext->buf[2] = (UINT4)0x98badcfe;
+  mdContext->buf[3] = (UINT4)0x10325476;
+}
+
+/* The routine MD5Update updates the message-digest context to
+   account for the presence of each of the characters inBuf[0..inLen-1]
+   in the message whose digest is being computed.
+ */
+void MD5Update (mdContext, inBuf, inLen)
+MD5_CTX *mdContext;
+unsigned const char *inBuf;
+unsigned int inLen;
+{
+  UINT4 in[16];
+  int mdi;
+  unsigned int i, ii;
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* update number of bits */
+  if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+    mdContext->i[1]++;
+  mdContext->i[0] += ((UINT4)inLen << 3);
+  mdContext->i[1] += ((UINT4)inLen >> 29);
+
+  while (inLen--) {
+    /* add new character to buffer, increment mdi */
+    mdContext->in[mdi++] = *inBuf++;
+
+    /* transform if necessary */
+    if (mdi == 0x40) {
+      for (i = 0, ii = 0; i < 16; i++, ii += 4)
+        in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+                (((UINT4)mdContext->in[ii+2]) << 16) |
+                (((UINT4)mdContext->in[ii+1]) << 8) |
+                ((UINT4)mdContext->in[ii]);
+      Transform (mdContext->buf, in);
+      mdi = 0;
+    }
+  }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+   ends with the desired message digest in mdContext->digest[0...15].
+ */
+
+void MD5Final (mdContext)
+MD5_CTX *mdContext;
+{
+  UINT4 in[16];
+  int mdi;
+  unsigned int i, ii;
+  unsigned int padLen;
+
+  /* save number of bits */
+  in[14] = mdContext->i[0];
+  in[15] = mdContext->i[1];
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* pad out to 56 mod 64 */
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+  MD5Update (mdContext, PADDING, padLen);
+
+  /* append length in bits and transform */
+  for (i = 0, ii = 0; i < 14; i++, ii += 4)
+    in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+            (((UINT4)mdContext->in[ii+2]) << 16) |
+            (((UINT4)mdContext->in[ii+1]) << 8) |
+            ((UINT4)mdContext->in[ii]);
+  Transform (mdContext->buf, in);
+
+  /* store buffer in digest */
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+    mdContext->digest[ii+1] =
+      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+    mdContext->digest[ii+2] =
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+    mdContext->digest[ii+3] =
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+  }
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (buf, in)
+UINT4 *buf;
+UINT4 *in;
+{
+  UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+  /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+  FF ( a, b, c, d, in[ 0], S11, 0xd76aa478); /* 1 */
+  FF ( d, a, b, c, in[ 1], S12, 0xe8c7b756); /* 2 */
+  FF ( c, d, a, b, in[ 2], S13, 0x242070db); /* 3 */
+  FF ( b, c, d, a, in[ 3], S14, 0xc1bdceee); /* 4 */
+  FF ( a, b, c, d, in[ 4], S11, 0xf57c0faf); /* 5 */
+  FF ( d, a, b, c, in[ 5], S12, 0x4787c62a); /* 6 */
+  FF ( c, d, a, b, in[ 6], S13, 0xa8304613); /* 7 */
+  FF ( b, c, d, a, in[ 7], S14, 0xfd469501); /* 8 */
+  FF ( a, b, c, d, in[ 8], S11, 0x698098d8); /* 9 */
+  FF ( d, a, b, c, in[ 9], S12, 0x8b44f7af); /* 10 */
+  FF ( c, d, a, b, in[10], S13, 0xffff5bb1); /* 11 */
+  FF ( b, c, d, a, in[11], S14, 0x895cd7be); /* 12 */
+  FF ( a, b, c, d, in[12], S11, 0x6b901122); /* 13 */
+  FF ( d, a, b, c, in[13], S12, 0xfd987193); /* 14 */
+  FF ( c, d, a, b, in[14], S13, 0xa679438e); /* 15 */
+  FF ( b, c, d, a, in[15], S14, 0x49b40821); /* 16 */
+
+  /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+  GG ( a, b, c, d, in[ 1], S21, 0xf61e2562); /* 17 */
+  GG ( d, a, b, c, in[ 6], S22, 0xc040b340); /* 18 */
+  GG ( c, d, a, b, in[11], S23, 0x265e5a51); /* 19 */
+  GG ( b, c, d, a, in[ 0], S24, 0xe9b6c7aa); /* 20 */
+  GG ( a, b, c, d, in[ 5], S21, 0xd62f105d); /* 21 */
+  GG ( d, a, b, c, in[10], S22,  0x2441453); /* 22 */
+  GG ( c, d, a, b, in[15], S23, 0xd8a1e681); /* 23 */
+  GG ( b, c, d, a, in[ 4], S24, 0xe7d3fbc8); /* 24 */
+  GG ( a, b, c, d, in[ 9], S21, 0x21e1cde6); /* 25 */
+  GG ( d, a, b, c, in[14], S22, 0xc33707d6); /* 26 */
+  GG ( c, d, a, b, in[ 3], S23, 0xf4d50d87); /* 27 */
+  GG ( b, c, d, a, in[ 8], S24, 0x455a14ed); /* 28 */
+  GG ( a, b, c, d, in[13], S21, 0xa9e3e905); /* 29 */
+  GG ( d, a, b, c, in[ 2], S22, 0xfcefa3f8); /* 30 */
+  GG ( c, d, a, b, in[ 7], S23, 0x676f02d9); /* 31 */
+  GG ( b, c, d, a, in[12], S24, 0x8d2a4c8a); /* 32 */
+
+  /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+  HH ( a, b, c, d, in[ 5], S31, 0xfffa3942); /* 33 */
+  HH ( d, a, b, c, in[ 8], S32, 0x8771f681); /* 34 */
+  HH ( c, d, a, b, in[11], S33, 0x6d9d6122); /* 35 */
+  HH ( b, c, d, a, in[14], S34, 0xfde5380c); /* 36 */
+  HH ( a, b, c, d, in[ 1], S31, 0xa4beea44); /* 37 */
+  HH ( d, a, b, c, in[ 4], S32, 0x4bdecfa9); /* 38 */
+  HH ( c, d, a, b, in[ 7], S33, 0xf6bb4b60); /* 39 */
+  HH ( b, c, d, a, in[10], S34, 0xbebfbc70); /* 40 */
+  HH ( a, b, c, d, in[13], S31, 0x289b7ec6); /* 41 */
+  HH ( d, a, b, c, in[ 0], S32, 0xeaa127fa); /* 42 */
+  HH ( c, d, a, b, in[ 3], S33, 0xd4ef3085); /* 43 */
+  HH ( b, c, d, a, in[ 6], S34,  0x4881d05); /* 44 */
+  HH ( a, b, c, d, in[ 9], S31, 0xd9d4d039); /* 45 */
+  HH ( d, a, b, c, in[12], S32, 0xe6db99e5); /* 46 */
+  HH ( c, d, a, b, in[15], S33, 0x1fa27cf8); /* 47 */
+  HH ( b, c, d, a, in[ 2], S34, 0xc4ac5665); /* 48 */
+
+  /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+  II ( a, b, c, d, in[ 0], S41, 0xf4292244); /* 49 */
+  II ( d, a, b, c, in[ 7], S42, 0x432aff97); /* 50 */
+  II ( c, d, a, b, in[14], S43, 0xab9423a7); /* 51 */
+  II ( b, c, d, a, in[ 5], S44, 0xfc93a039); /* 52 */
+  II ( a, b, c, d, in[12], S41, 0x655b59c3); /* 53 */
+  II ( d, a, b, c, in[ 3], S42, 0x8f0ccc92); /* 54 */
+  II ( c, d, a, b, in[10], S43, 0xffeff47d); /* 55 */
+  II ( b, c, d, a, in[ 1], S44, 0x85845dd1); /* 56 */
+  II ( a, b, c, d, in[ 8], S41, 0x6fa87e4f); /* 57 */
+  II ( d, a, b, c, in[15], S42, 0xfe2ce6e0); /* 58 */
+  II ( c, d, a, b, in[ 6], S43, 0xa3014314); /* 59 */
+  II ( b, c, d, a, in[13], S44, 0x4e0811a1); /* 60 */
+  II ( a, b, c, d, in[ 4], S41, 0xf7537e82); /* 61 */
+  II ( d, a, b, c, in[11], S42, 0xbd3af235); /* 62 */
+  II ( c, d, a, b, in[ 2], S43, 0x2ad7d2bb); /* 63 */
+  II ( b, c, d, a, in[ 9], S44, 0xeb86d391); /* 64 */
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
+
+/*
+ ***********************************************************************
+ ** End of md5.c                                                      **
+ ******************************** (cut) ********************************
+ */
diff --git a/chrony_3_3/md5.h b/chrony_3_3/md5.h
new file mode 100644
index 0000000..5f37235
--- /dev/null
+++ b/chrony_3_3/md5.h
@@ -0,0 +1,56 @@
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5                    **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               **
+ ** Revised (for MD5): RLR 4/27/91                                    **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#include "sysincl.h"
+
+/* typedef a 32-bit type */
+typedef uint32_t UINT4;
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+  UINT4 i[2];                   /* number of _bits_ handled mod 2^64 */
+  UINT4 buf[4];                                    /* scratch buffer */
+  unsigned char in[64];                              /* input buffer */
+  unsigned char digest[16];     /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5Init (MD5_CTX *mdContext);
+void MD5Update (MD5_CTX *, unsigned const char *, unsigned int);
+void MD5Final (MD5_CTX *);
+
+/*
+ ***********************************************************************
+ ** End of md5.h                                                      **
+ ******************************** (cut) ********************************
+ */
diff --git a/chrony_3_3/memory.c b/chrony_3_3/memory.c
new file mode 100644
index 0000000..03366e5
--- /dev/null
+++ b/chrony_3_3/memory.c
@@ -0,0 +1,93 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2014, 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Utility functions for memory allocation.
+
+  */
+
+#include "config.h"
+
+#include "logging.h"
+#include "memory.h"
+
+void *
+Malloc(size_t size)
+{
+  void *r;
+
+  r = malloc(size);
+  if (!r && size)
+    LOG_FATAL("Could not allocate memory");
+
+  return r;
+}
+
+void *
+Realloc(void *ptr, size_t size)
+{
+  void *r;
+
+  r = realloc(ptr, size);
+  if (!r && size)
+    LOG_FATAL("Could not allocate memory");
+
+  return r;
+}
+
+static size_t
+get_array_size(size_t nmemb, size_t size)
+{
+  size_t array_size;
+
+  array_size = nmemb * size;
+
+  /* Check for overflow */
+  if (nmemb > 0 && array_size / nmemb != size)
+    LOG_FATAL("Could not allocate memory");
+
+  return array_size;
+}
+
+void *
+Malloc2(size_t nmemb, size_t size)
+{
+  return Malloc(get_array_size(nmemb, size));
+}
+
+void *
+Realloc2(void *ptr, size_t nmemb, size_t size)
+{
+  return Realloc(ptr, get_array_size(nmemb, size));
+}
+
+char *
+Strdup(const char *s)
+{
+  void *r;
+
+  r = strdup(s);
+  if (!r)
+    LOG_FATAL("Could not allocate memory");
+
+  return r;
+}
diff --git a/chrony_3_3/memory.h b/chrony_3_3/memory.h
new file mode 100644
index 0000000..110cf6a
--- /dev/null
+++ b/chrony_3_3/memory.h
@@ -0,0 +1,43 @@
+/*
+  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 memory functions
+  */
+
+#ifndef GOT_MEMORY_H
+#define GOT_MEMORY_H
+
+/* Wrappers checking for errors */
+extern void *Malloc(size_t size);
+extern void *Realloc(void *ptr, size_t size);
+extern void *Malloc2(size_t nmemb, size_t size);
+extern void *Realloc2(void *ptr, size_t nmemb, size_t size);
+extern char *Strdup(const char *s);
+
+/* Convenient macros */
+#define MallocNew(T) ((T *) Malloc(sizeof(T)))
+#define MallocArray(T, n) ((T *) Malloc2(n, sizeof(T)))
+#define ReallocArray(T, n, x) ((T *) Realloc2((void *)(x), n, sizeof(T)))
+#define Free(x) free(x)
+
+#endif /* GOT_MEMORY_H */
diff --git a/chrony_3_3/nameserv.c b/chrony_3_3/nameserv.c
new file mode 100644
index 0000000..1cb9608
--- /dev/null
+++ b/chrony_3_3/nameserv.c
@@ -0,0 +1,200 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2009-2011
+ * 
+ * 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 to do name to IP address conversion
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "nameserv.h"
+#include "util.h"
+
+/* ================================================== */
+
+static int address_family = IPADDR_UNSPEC;
+
+void
+DNS_SetAddressFamily(int family)
+{
+  address_family = family;
+}
+
+DNS_Status 
+DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
+{
+#ifdef HAVE_GETADDRINFO
+  struct addrinfo hints, *res, *ai;
+  int i, result;
+
+  max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
+
+  memset(&hints, 0, sizeof (hints));
+
+  switch (address_family) {
+    case IPADDR_INET4:
+      hints.ai_family = AF_INET;
+      break;
+#ifdef FEAT_IPV6
+    case IPADDR_INET6:
+      hints.ai_family = AF_INET6;
+      break;
+#endif
+    default:
+      hints.ai_family = AF_UNSPEC;
+  }
+  hints.ai_socktype = SOCK_STREAM;
+
+  result = getaddrinfo(name, NULL, &hints, &res);
+
+  if (result) {
+#ifdef FORCE_DNSRETRY
+    return DNS_TryAgain;
+#else
+    return result == EAI_AGAIN ? DNS_TryAgain : DNS_Failure;
+#endif
+  }
+
+  for (ai = res, i = 0; i < max_addrs && ai != NULL; ai = ai->ai_next) {
+    switch (ai->ai_family) {
+      case AF_INET:
+        if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4)
+          continue;
+        ip_addrs[i].family = IPADDR_INET4;
+        ip_addrs[i].addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr);
+        i++;
+        break;
+#ifdef FEAT_IPV6
+      case AF_INET6:
+        if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET6)
+          continue;
+        ip_addrs[i].family = IPADDR_INET6;
+        memcpy(&ip_addrs[i].addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr,
+               sizeof (ip_addrs->addr.in6));
+        i++;
+        break;
+#endif
+    }
+  }
+
+  for (; i < max_addrs; i++)
+        ip_addrs[i].family = IPADDR_UNSPEC;
+
+  freeaddrinfo(res);
+
+  return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure;
+#else
+  struct hostent *host;
+  int i;
+  
+  if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4)
+    return DNS_Failure;
+
+  max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
+
+  host = gethostbyname(name);
+
+  if (host == NULL) {
+    if (h_errno == TRY_AGAIN)
+      return DNS_TryAgain;
+  } else {
+    if (host->h_addrtype != AF_INET || !host->h_addr_list[0])
+      return DNS_Failure;
+
+    for (i = 0; host->h_addr_list[i] && i < max_addrs; i++) {
+      ip_addrs[i].family = IPADDR_INET4;
+      ip_addrs[i].addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[i]);
+    }
+
+    for (; i < max_addrs; i++)
+      ip_addrs[i].family = IPADDR_UNSPEC;
+
+    return DNS_Success;
+  }
+
+#ifdef FORCE_DNSRETRY
+  return DNS_TryAgain;
+#else
+  return DNS_Failure;
+#endif
+
+#endif
+}
+
+/* ================================================== */
+
+int
+DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
+{
+  char *result = NULL;
+
+#ifdef FEAT_IPV6
+  struct sockaddr_in6 in6;
+  socklen_t slen;
+  char hbuf[NI_MAXHOST];
+
+  slen = UTI_IPAndPortToSockaddr(ip_addr, 0, (struct sockaddr *)&in6);
+  if (!getnameinfo((struct sockaddr *)&in6, slen, hbuf, sizeof (hbuf), NULL, 0, 0))
+    result = hbuf;
+#else
+  struct hostent *host;
+  uint32_t addr;
+
+  switch (ip_addr->family) {
+    case IPADDR_INET4:
+      addr = htonl(ip_addr->addr.in4);
+      host = gethostbyaddr((const char *) &addr, sizeof (ip_addr), AF_INET);
+      break;
+#ifdef FEAT_IPV6
+    case IPADDR_INET6:
+      host = gethostbyaddr((const void *) ip_addr->addr.in6, sizeof (ip_addr->addr.in6), AF_INET6);
+      break;
+#endif
+    default:
+      host = NULL;
+  }
+  if (host)
+    result = host->h_name;
+#endif
+
+  if (result == NULL)
+    result = UTI_IPToString(ip_addr);
+  if (snprintf(name, len, "%s", result) >= len)
+    return 0;
+
+  return 1;
+}
+
+/* ================================================== */
+
+void
+DNS_Reload(void)
+{
+  res_init();
+}
+
+/* ================================================== */
+
diff --git a/chrony_3_3/nameserv.h b/chrony_3_3/nameserv.h
new file mode 100644
index 0000000..dbef61a
--- /dev/null
+++ b/chrony_3_3/nameserv.h
@@ -0,0 +1,52 @@
+/*
+  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 header for nameserver functions
+  */
+
+
+#ifndef GOT_NAMESERV_H
+#define GOT_NAMESERV_H
+
+#include "addressing.h"
+
+typedef enum {
+  DNS_Success,
+  DNS_TryAgain,
+  DNS_Failure
+} DNS_Status;
+
+/* Resolve names only to selected address family */
+extern void DNS_SetAddressFamily(int family);
+
+/* Maximum number of addresses returned by DNS_Name2IPAddress */
+#define DNS_MAX_ADDRESSES 16
+
+extern DNS_Status DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs);
+
+extern int DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len);
+
+extern void DNS_Reload(void);
+
+#endif /* GOT_NAMESERV_H */
+
diff --git a/chrony_3_3/nameserv_async.c b/chrony_3_3/nameserv_async.c
new file mode 100644
index 0000000..9ad3d17
--- /dev/null
+++ b/chrony_3_3/nameserv_async.c
@@ -0,0 +1,133 @@
+/*
+  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 to asynchronously convert name to IP address
+
+  */
+
+#include "config.h"
+#include "sysincl.h"
+
+#include "nameserv_async.h"
+#include "logging.h"
+#include "memory.h"
+#include "privops.h"
+#include "sched.h"
+#include "util.h"
+
+#ifdef USE_PTHREAD_ASYNCDNS
+#include <pthread.h>
+
+/* ================================================== */
+
+struct DNS_Async_Instance {
+  const char *name;
+  DNS_Status status;
+  IPAddr addresses[DNS_MAX_ADDRESSES];
+  DNS_NameResolveHandler handler;
+  void *arg;
+
+  pthread_t thread;
+  int pipe[2];
+};
+
+static int resolving_threads = 0;
+
+/* ================================================== */
+
+static void *
+start_resolving(void *anything)
+{
+  struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
+
+  inst->status = PRV_Name2IPAddress(inst->name, inst->addresses, DNS_MAX_ADDRESSES);
+
+  /* Notify the main thread that the result is ready */
+  if (write(inst->pipe[1], "", 1) < 0)
+    ;
+
+  return NULL;
+}
+
+/* ================================================== */
+
+static void
+end_resolving(int fd, int event, void *anything)
+{
+  struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
+  int i;
+
+  if (pthread_join(inst->thread, NULL)) {
+    LOG_FATAL("pthread_join() failed");
+  }
+
+  resolving_threads--;
+
+  SCH_RemoveFileHandler(inst->pipe[0]);
+  close(inst->pipe[0]);
+  close(inst->pipe[1]);
+
+  for (i = 0; inst->status == DNS_Success && i < DNS_MAX_ADDRESSES &&
+              inst->addresses[i].family != IPADDR_UNSPEC; i++)
+    ;
+
+  (inst->handler)(inst->status, i, inst->addresses, inst->arg);
+
+  Free(inst);
+}
+
+/* ================================================== */
+
+void
+DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
+{
+  struct DNS_Async_Instance *inst;
+
+  inst = MallocNew(struct DNS_Async_Instance);
+  inst->name = name;
+  inst->handler = handler;
+  inst->arg = anything;
+  inst->status = DNS_Failure;
+
+  if (pipe(inst->pipe)) {
+    LOG_FATAL("pipe() failed");
+  }
+
+  UTI_FdSetCloexec(inst->pipe[0]);
+  UTI_FdSetCloexec(inst->pipe[1]);
+
+  resolving_threads++;
+  assert(resolving_threads <= 1);
+
+  if (pthread_create(&inst->thread, NULL, start_resolving, inst)) {
+    LOG_FATAL("pthread_create() failed");
+  }
+
+  SCH_AddFileHandler(inst->pipe[0], SCH_FILE_INPUT, end_resolving, inst);
+}
+
+/* ================================================== */
+
+#else
+#error
+#endif
diff --git a/chrony_3_3/nameserv_async.h b/chrony_3_3/nameserv_async.h
new file mode 100644
index 0000000..b8479e1
--- /dev/null
+++ b/chrony_3_3/nameserv_async.h
@@ -0,0 +1,40 @@
+/*
+  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 for asynchronous nameserver functions
+  */
+
+
+#ifndef GOT_NAMESERV_ASYNC_H
+#define GOT_NAMESERV_ASYNC_H
+
+#include "nameserv.h"
+
+/* Function type for callback to process the result */
+typedef void (*DNS_NameResolveHandler)(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *anything);
+
+/* Request resolving of a name to IP address. The handler will be
+   called when the result is available. */
+extern void DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything);
+
+#endif
diff --git a/chrony_3_3/ntp.h b/chrony_3_3/ntp.h
new file mode 100644
index 0000000..801f264
--- /dev/null
+++ b/chrony_3_3/ntp.h
@@ -0,0 +1,124 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Header file containing common NTP bits and pieces
+  */
+
+#ifndef GOT_NTP_H
+#define GOT_NTP_H
+
+#include "sysincl.h"
+
+#include "hash.h"
+
+typedef struct {
+  uint32_t hi;
+  uint32_t lo;
+} NTP_int64;
+
+typedef uint32_t NTP_int32;
+
+/* The UDP port number used by NTP */
+#define NTP_PORT 123
+
+/* The NTP protocol version that we support */
+#define NTP_VERSION 4
+
+/* Maximum stratum number (infinity) */
+#define NTP_MAX_STRATUM 16
+
+/* The minimum valid length of an extension field */
+#define NTP_MIN_EXTENSION_LENGTH 16
+
+/* The maximum assumed length of all extension fields in received
+   packets (RFC 5905 doesn't specify a limit on length or number of
+   extension fields in one packet) */
+#define NTP_MAX_EXTENSIONS_LENGTH 1024
+
+/* The minimum and maximum supported length of MAC */
+#define NTP_MIN_MAC_LENGTH (4 + 16)
+#define NTP_MAX_MAC_LENGTH (4 + MAX_HASH_LENGTH)
+
+/* The maximum length of MAC in NTPv4 packets which allows deterministic
+   parsing of extension fields (RFC 7822) */
+#define NTP_MAX_V4_MAC_LENGTH (4 + 20)
+
+/* Type definition for leap bits */
+typedef enum {
+  LEAP_Normal = 0,
+  LEAP_InsertSecond = 1,
+  LEAP_DeleteSecond = 2,
+  LEAP_Unsynchronised = 3
+} NTP_Leap;
+
+typedef enum {
+  MODE_UNDEFINED = 0,
+  MODE_ACTIVE = 1,
+  MODE_PASSIVE = 2,
+  MODE_CLIENT = 3,
+  MODE_SERVER = 4,
+  MODE_BROADCAST = 5
+} NTP_Mode;
+
+typedef struct {
+  uint8_t lvm;
+  uint8_t stratum;
+  int8_t poll;
+  int8_t precision;
+  NTP_int32 root_delay;
+  NTP_int32 root_dispersion;
+  NTP_int32 reference_id;
+  NTP_int64 reference_ts;
+  NTP_int64 originate_ts;
+  NTP_int64 receive_ts;
+  NTP_int64 transmit_ts;
+
+  /* Optional extension fields, we don't send packets with them yet */
+  /* uint8_t extensions[] */
+
+  /* Optional message authentication code (MAC) */
+  NTP_int32 auth_keyid;
+  uint8_t auth_data[NTP_MAX_MAC_LENGTH - 4];
+} NTP_Packet;
+
+#define NTP_NORMAL_PACKET_LENGTH (int)offsetof(NTP_Packet, auth_keyid)
+
+/* The buffer used to hold a datagram read from the network */
+typedef struct {
+  NTP_Packet ntp_pkt;
+  uint8_t extensions[NTP_MAX_EXTENSIONS_LENGTH];
+} NTP_Receive_Buffer;
+
+/* Macros to work with the lvm field */
+#define NTP_LVM_TO_LEAP(lvm) (((lvm) >> 6) & 0x3)
+#define NTP_LVM_TO_VERSION(lvm) (((lvm) >> 3) & 0x7)
+#define NTP_LVM_TO_MODE(lvm) ((lvm) & 0x7)
+#define NTP_LVM(leap, version, mode) \
+  ((((leap) << 6) & 0xc0) | (((version) << 3) & 0x38) | ((mode) & 0x07))
+
+/* Special NTP reference IDs */
+#define NTP_REFID_UNSYNC 0x0UL
+#define NTP_REFID_LOCAL 0x7F7F0101UL /* 127.127.1.1 */
+#define NTP_REFID_SMOOTH 0x7F7F01FFUL /* 127.127.1.255 */
+
+#endif /* GOT_NTP_H */
diff --git a/chrony_3_3/ntp_core.c b/chrony_3_3/ntp_core.c
new file mode 100644
index 0000000..c82d792
--- /dev/null
+++ b/chrony_3_3/ntp_core.c
@@ -0,0 +1,2614 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Core NTP protocol engine
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "array.h"
+#include "ntp_core.h"
+#include "ntp_io.h"
+#include "ntp_signd.h"
+#include "memory.h"
+#include "sched.h"
+#include "reference.h"
+#include "local.h"
+#include "smooth.h"
+#include "sources.h"
+#include "util.h"
+#include "conf.h"
+#include "logging.h"
+#include "keys.h"
+#include "addrfilt.h"
+#include "clientlog.h"
+
+/* ================================================== */
+
+static LOG_FileID logfileid;
+static int log_raw_measurements;
+
+/* ================================================== */
+/* Enumeration used for remembering the operating mode of one of the
+   sources */
+
+typedef enum {
+  MD_OFFLINE,                   /* No sampling at all */
+  MD_ONLINE,                    /* Normal sampling based on sampling interval */
+  MD_BURST_WAS_OFFLINE,         /* Burst sampling, return to offline afterwards */
+  MD_BURST_WAS_ONLINE,          /* Burst sampling, return to online afterwards */
+} OperatingMode;
+
+/* ================================================== */
+/* Enumeration for authentication modes of NTP packets */
+
+typedef enum {
+  AUTH_NONE = 0,                /* No authentication */
+  AUTH_SYMMETRIC,               /* MAC using symmetric key (RFC 1305, RFC 5905) */
+  AUTH_MSSNTP,                  /* MS-SNTP authenticator field */
+  AUTH_MSSNTP_EXT,              /* MS-SNTP extended authenticator field */
+} AuthenticationMode;
+
+/* ================================================== */
+/* Structure used for holding a single peer/server's
+   protocol machine */
+
+struct NCR_Instance_Record {
+  NTP_Remote_Address remote_addr; /* Needed for routing transmit packets */
+  NTP_Local_Address local_addr; /* Local address/socket used to send packets */
+  NTP_Mode mode;                /* The source's NTP mode
+                                   (client/server or symmetric active peer) */
+  int interleaved;              /* Boolean enabling interleaved NTP mode */
+  OperatingMode opmode;         /* Whether we are sampling this source
+                                   or not and in what way */
+  SCH_TimeoutID rx_timeout_id;  /* Timeout ID for latest received response */
+  SCH_TimeoutID tx_timeout_id;  /* Timeout ID for next transmission */
+  int tx_suspended;             /* Boolean indicating we can't transmit yet */
+
+  int auto_burst;               /* If 1, initiate a burst on each poll */
+  int auto_offline;             /* If 1, automatically go offline if server/peer
+                                   isn't responding */
+
+  int local_poll;               /* Log2 of polling interval at our end */
+  int remote_poll;              /* Log2 of server/peer's polling interval (recovered
+                                   from received packets) */
+  int remote_stratum;           /* Stratum of the server/peer (recovered from
+                                   received packets) */
+
+  int presend_minpoll;           /* If the current polling interval is
+                                    at least this, an extra client packet
+                                    will be send some time before normal
+                                    transmit.  This ensures that both
+                                    us and the server/peer have an ARP
+                                    entry for each other ready, which
+                                    means our measurement is not
+                                    botched by an ARP round-trip on one
+                                    side or the other. */
+
+  int presend_done;             /* The presend packet has been sent */
+
+  int minpoll;                  /* Log2 of minimum defined polling interval */
+  int maxpoll;                  /* Log2 of maximum defined polling interval */
+
+  int min_stratum;              /* Increase stratum in received packets to the
+                                   minimum */
+
+  int poll_target;              /* Target number of sourcestats samples */
+
+  int version;                  /* Version set in packets for server/peer */
+
+  double poll_score;            /* Score of current local poll */
+
+  double max_delay;             /* Maximum round-trip delay to the
+                                   peer that we can tolerate and still
+                                   use the sample for generating
+                                   statistics from */
+
+  double max_delay_ratio;       /* Largest ratio of delay /
+                                   min_delay_in_register that we can
+                                   tolerate.  */
+
+  double max_delay_dev_ratio;   /* Maximum ratio of increase in delay / stddev */
+
+  double offset_correction;     /* Correction applied to measured offset
+                                   (e.g. for asymmetry in network delay) */
+
+  AuthenticationMode auth_mode; /* Authentication mode of our requests */
+  uint32_t auth_key_id;          /* The ID of the authentication key to
+                                   use. */
+
+  /* Count of transmitted packets since last valid response */
+  unsigned int tx_count;
+
+  /* Flag indicating a valid response was received since last request */
+  int valid_rx;
+
+  /* Flag indicating the timestamps below are from a valid packet and may
+     be used for synchronisation */
+  int valid_timestamps;
+
+  /* Receive and transmit timestamps from the last valid response */
+  NTP_int64 remote_ntp_rx;
+  NTP_int64 remote_ntp_tx;
+
+  /* Local timestamp when the last valid response was received from the
+     source.  We have to be prepared to tinker with this if the local
+     clock has its frequency adjusted before we repond.  The value we
+     store here is what our own local time was when the same arrived.
+     Before replying, we have to correct this to fit with the
+     parameters for the current reference.  (It must be stored
+     relative to local time to permit frequency and offset adjustments
+     to be made when we trim the local clock). */
+  NTP_int64 local_ntp_rx;
+  NTP_Local_Timestamp local_rx;
+
+  /* Local timestamp when we last transmitted a packet to the source.
+     We store two versions.  The first is in NTP format, and is used
+     to validate the next received packet from the source.
+     Additionally, this is corrected to bring it into line with the
+     current reference.  The second is in timespec format, and is kept
+     relative to the local clock.  We modify this in accordance with
+     local clock frequency/offset changes, and use this for computing
+     statistics about the source when a return packet arrives. */
+  NTP_int64 local_ntp_tx;
+  NTP_Local_Timestamp local_tx;
+
+  /* Previous values of some variables needed in interleaved mode */
+  NTP_Local_Timestamp prev_local_tx;
+  int prev_local_poll;
+  unsigned int prev_tx_count;
+
+  /* Flag indicating the two timestamps below were updated since the
+     last transmission */
+  int updated_init_timestamps;
+
+  /* Timestamps used for (re)starting the symmetric protocol, when we
+     need to respond to a packet which is not a valid response */
+  NTP_int64 init_remote_ntp_tx;
+  NTP_Local_Timestamp init_local_rx;
+
+  /* The instance record in the main source management module.  This
+     performs the statistical analysis on the samples we generate */
+
+  SRC_Instance source;
+
+  int burst_good_samples_to_go;
+  int burst_total_samples_to_go;
+
+  /* Report from last valid response */
+  RPT_NTPReport report;
+};
+
+typedef struct {
+  NTP_Remote_Address addr;
+  NTP_Local_Address local_addr;
+  int interval;
+} BroadcastDestination;
+
+/* Array of BroadcastDestination */
+static ARR_Instance broadcasts;
+
+/* ================================================== */
+/* Initial delay period before first packet is transmitted (in seconds) */
+#define INITIAL_DELAY 0.2
+
+/* Spacing required between samples for any two servers/peers (to
+   minimise risk of network collisions) (in seconds) */
+#define MIN_SAMPLING_SEPARATION 0.02
+#define MAX_SAMPLING_SEPARATION 0.2
+
+/* Randomness added to spacing between samples for one server/peer */
+#define SAMPLING_RANDOMNESS 0.02
+
+/* Adjustment of the peer polling interval */
+#define PEER_SAMPLING_ADJ 1.1
+
+/* Spacing between samples in burst mode for one server/peer */
+#define BURST_INTERVAL 2.0
+
+/* Time to wait before retransmitting in burst mode, if we did not get
+   a reply to the previous probe */
+#define BURST_TIMEOUT 2.0
+
+/* Number of samples in initial burst */
+#define IBURST_GOOD_SAMPLES 4
+#define IBURST_TOTAL_SAMPLES SOURCE_REACH_BITS
+
+/* Number of samples in automatic burst */
+#define BURST_GOOD_SAMPLES 1
+#define MAX_BURST_TOTAL_SAMPLES 4
+
+/* Time to wait after sending packet to 'warm up' link */
+#define WARM_UP_DELAY 2.0
+
+/* Compatible NTP protocol versions */
+#define NTP_MAX_COMPAT_VERSION NTP_VERSION
+#define NTP_MIN_COMPAT_VERSION 1
+
+/* Maximum allowed dispersion - as defined in RFC 5905 (16 seconds) */
+#define NTP_MAX_DISPERSION 16.0
+
+/* Invalid stratum number */
+#define NTP_INVALID_STRATUM 0
+
+/* Maximum allowed time for server to process client packet */
+#define MAX_SERVER_INTERVAL 4.0
+
+/* Maximum acceptable delay in transmission for timestamp correction */
+#define MAX_TX_DELAY 1.0
+
+/* Maximum allowed values of maxdelay parameters */
+#define MAX_MAXDELAY 1.0e3
+#define MAX_MAXDELAYRATIO 1.0e6
+#define MAX_MAXDELAYDEVRATIO 1.0e6
+
+/* Minimum and maximum allowed poll interval */
+#define MIN_MINPOLL -4
+#define MIN_MAXPOLL 0
+#define MAX_POLL 24
+
+/* Kiss-o'-Death codes */
+#define KOD_RATE 0x52415445UL /* RATE */
+
+/* Maximum poll interval set by KoD RATE */
+#define MAX_KOD_RATE_POLL SRC_DEFAULT_MAXPOLL
+
+/* Maximum number of missed responses to follow peer's polling interval */
+#define MAX_PEER_POLL_TX 8
+
+/* Maximum number of missed responses to accept samples using old timestamps
+   in the interleaved client/server mode */
+#define MAX_CLIENT_INTERLEAVED_TX 4
+
+/* Maximum ratio of local intervals in the timestamp selection of the
+   interleaved mode to prefer a sample using previous timestamps */
+#define MAX_INTERLEAVED_L2L_RATIO 0.1
+
+/* Invalid socket, different from the one in ntp_io.c */
+#define INVALID_SOCK_FD -2
+
+/* ================================================== */
+
+/* Server IPv4/IPv6 sockets */
+static int server_sock_fd4;
+static int server_sock_fd6;
+
+static ADF_AuthTable access_auth_table;
+
+/* Characters for printing synchronisation status and timestamping source */
+static const char leap_chars[4] = {'N', '+', '-', '?'};
+static const char tss_chars[3] = {'D', 'K', 'H'};
+
+/* ================================================== */
+/* Forward prototypes */
+
+static void transmit_timeout(void *arg);
+static double get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx);
+static double get_separation(int poll);
+
+/* ================================================== */
+
+static void
+do_size_checks(void)
+{
+  /* Assertions to check the sizes of certain data types
+     and the positions of certain record fields */
+
+  /* Check that certain invariants are true */
+  assert(sizeof(NTP_int32) == 4);
+  assert(sizeof(NTP_int64) == 8);
+
+  /* Check offsets of all fields in the NTP packet format */
+  assert(offsetof(NTP_Packet, lvm)             ==  0);
+  assert(offsetof(NTP_Packet, stratum)         ==  1);
+  assert(offsetof(NTP_Packet, poll)            ==  2);
+  assert(offsetof(NTP_Packet, precision)       ==  3);
+  assert(offsetof(NTP_Packet, root_delay)      ==  4);
+  assert(offsetof(NTP_Packet, root_dispersion) ==  8);
+  assert(offsetof(NTP_Packet, reference_id)    == 12);
+  assert(offsetof(NTP_Packet, reference_ts)    == 16);
+  assert(offsetof(NTP_Packet, originate_ts)    == 24);
+  assert(offsetof(NTP_Packet, receive_ts)      == 32);
+  assert(offsetof(NTP_Packet, transmit_ts)     == 40);
+}
+
+/* ================================================== */
+
+static void
+do_time_checks(void)
+{
+  struct timespec now;
+  time_t warning_advance = 3600 * 24 * 365 * 10; /* 10 years */
+
+#ifdef HAVE_LONG_TIME_T
+  /* Check that time before NTP_ERA_SPLIT underflows correctly */
+
+  struct timespec ts1 = {NTP_ERA_SPLIT, 1}, ts2 = {NTP_ERA_SPLIT - 1, 1};
+  NTP_int64 nts1, nts2;
+  int r;
+
+  UTI_TimespecToNtp64(&ts1, &nts1, NULL);
+  UTI_TimespecToNtp64(&ts2, &nts2, NULL);
+  UTI_Ntp64ToTimespec(&nts1, &ts1);
+  UTI_Ntp64ToTimespec(&nts2, &ts2);
+
+  r = ts1.tv_sec == NTP_ERA_SPLIT &&
+      ts1.tv_sec + (1ULL << 32) - 1 == ts2.tv_sec;
+
+  assert(r);
+
+  LCL_ReadRawTime(&now);
+  if (ts2.tv_sec - now.tv_sec < warning_advance)
+    LOG(LOGS_WARN, "Assumed NTP time ends at %s!", UTI_TimeToLogForm(ts2.tv_sec));
+#else
+  LCL_ReadRawTime(&now);
+  if (now.tv_sec > 0x7fffffff - warning_advance)
+    LOG(LOGS_WARN, "System time ends at %s!", UTI_TimeToLogForm(0x7fffffff));
+#endif
+}
+
+/* ================================================== */
+
+static void
+zero_local_timestamp(NTP_Local_Timestamp *ts)
+{
+  UTI_ZeroTimespec(&ts->ts);
+  ts->err = 0.0;
+  ts->source = NTP_TS_DAEMON;
+}
+
+/* ================================================== */
+
+void
+NCR_Initialise(void)
+{
+  do_size_checks();
+  do_time_checks();
+
+  logfileid = CNF_GetLogMeasurements(&log_raw_measurements) ? LOG_FileOpen("measurements",
+      "   Date (UTC) Time     IP Address   L St 123 567 ABCD  LP RP Score    Offset  Peer del. Peer disp.  Root del. Root disp. Refid     MTxRx")
+    : -1;
+
+  access_auth_table = ADF_CreateTable();
+  broadcasts = ARR_CreateInstance(sizeof (BroadcastDestination));
+
+  /* Server socket will be opened when access is allowed */
+  server_sock_fd4 = INVALID_SOCK_FD;
+  server_sock_fd6 = INVALID_SOCK_FD;
+}
+
+/* ================================================== */
+
+void
+NCR_Finalise(void)
+{
+  unsigned int i;
+
+  if (server_sock_fd4 != INVALID_SOCK_FD)
+    NIO_CloseServerSocket(server_sock_fd4);
+  if (server_sock_fd6 != INVALID_SOCK_FD)
+    NIO_CloseServerSocket(server_sock_fd6);
+
+  for (i = 0; i < ARR_GetSize(broadcasts); i++)
+    NIO_CloseServerSocket(((BroadcastDestination *)ARR_GetElement(broadcasts, i))->local_addr.sock_fd);
+
+  ARR_DestroyInstance(broadcasts);
+  ADF_DestroyTable(access_auth_table);
+}
+
+/* ================================================== */
+
+static void
+restart_timeout(NCR_Instance inst, double delay)
+{
+  /* Check if we can transmit */
+  if (inst->tx_suspended) {
+    assert(!inst->tx_timeout_id);
+    return;
+  }
+
+  /* Stop both rx and tx timers if running */
+  SCH_RemoveTimeout(inst->rx_timeout_id);
+  inst->rx_timeout_id = 0;
+  SCH_RemoveTimeout(inst->tx_timeout_id);
+
+  /* Start new timer for transmission */
+  inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, get_separation(inst->local_poll),
+                                              SAMPLING_RANDOMNESS,
+                                              inst->mode == MODE_CLIENT ?
+                                                SCH_NtpClientClass : SCH_NtpPeerClass,
+                                              transmit_timeout, (void *)inst);
+}
+
+/* ================================================== */
+
+static void
+start_initial_timeout(NCR_Instance inst)
+{
+  double delay, last_tx;
+  struct timespec now;
+
+  if (!inst->tx_timeout_id) {
+    /* This will be the first transmission after mode change */
+
+    /* Mark source active */
+    SRC_SetActive(inst->source);
+  }
+
+  /* In case the offline period was too short, adjust the delay to keep
+     the interval between packets at least as long as the current polling
+     interval */
+  SCH_GetLastEventTime(&now, NULL, NULL);
+  last_tx = UTI_DiffTimespecsToDouble(&now, &inst->local_tx.ts);
+  if (last_tx < 0.0)
+    last_tx = 0.0;
+  delay = get_transmit_delay(inst, 0, 0.0) - last_tx;
+  if (delay < INITIAL_DELAY)
+    delay = INITIAL_DELAY;
+
+  restart_timeout(inst, delay);
+}
+
+/* ================================================== */
+
+static void
+close_client_socket(NCR_Instance inst)
+{
+  if (inst->mode == MODE_CLIENT && inst->local_addr.sock_fd != INVALID_SOCK_FD) {
+    NIO_CloseClientSocket(inst->local_addr.sock_fd);
+    inst->local_addr.sock_fd = INVALID_SOCK_FD;
+  }
+
+  SCH_RemoveTimeout(inst->rx_timeout_id);
+  inst->rx_timeout_id = 0;
+}
+
+/* ================================================== */
+
+static void
+take_offline(NCR_Instance inst)
+{
+  inst->opmode = MD_OFFLINE;
+
+  SCH_RemoveTimeout(inst->tx_timeout_id);
+  inst->tx_timeout_id = 0;
+
+  /* Mark source unreachable */
+  SRC_ResetReachability(inst->source);
+
+  /* And inactive */
+  SRC_UnsetActive(inst->source);
+
+  close_client_socket(inst);
+
+  NCR_ResetInstance(inst);
+}
+
+/* ================================================== */
+
+NCR_Instance
+NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
+{
+  NCR_Instance result;
+
+  result = MallocNew(struct NCR_Instance_Record);
+
+  result->remote_addr = *remote_addr;
+  result->local_addr.ip_addr.family = IPADDR_UNSPEC;
+  result->local_addr.if_index = INVALID_IF_INDEX;
+
+  switch (type) {
+    case NTP_SERVER:
+      /* Client socket will be obtained when sending request */
+      result->local_addr.sock_fd = INVALID_SOCK_FD;
+      result->mode = MODE_CLIENT;
+      break;
+    case NTP_PEER:
+      result->local_addr.sock_fd = NIO_OpenServerSocket(remote_addr);
+      result->mode = MODE_ACTIVE;
+      break;
+    default:
+      assert(0);
+  }
+
+  result->interleaved = params->interleaved;
+
+  result->minpoll = params->minpoll;
+  if (result->minpoll < MIN_MINPOLL)
+    result->minpoll = SRC_DEFAULT_MINPOLL;
+  else if (result->minpoll > MAX_POLL)
+    result->minpoll = MAX_POLL;
+  result->maxpoll = params->maxpoll;
+  if (result->maxpoll < MIN_MAXPOLL)
+    result->maxpoll = SRC_DEFAULT_MAXPOLL;
+  else if (result->maxpoll > MAX_POLL)
+    result->maxpoll = MAX_POLL;
+  if (result->maxpoll < result->minpoll)
+    result->maxpoll = result->minpoll;
+
+  result->min_stratum = params->min_stratum;
+  if (result->min_stratum >= NTP_MAX_STRATUM)
+    result->min_stratum = NTP_MAX_STRATUM - 1;
+
+  /* Presend doesn't work in symmetric mode */
+  result->presend_minpoll = params->presend_minpoll;
+  if (result->presend_minpoll <= MAX_POLL && result->mode != MODE_CLIENT)
+    result->presend_minpoll = MAX_POLL + 1;
+
+  result->max_delay = CLAMP(0.0, params->max_delay, MAX_MAXDELAY);
+  result->max_delay_ratio = CLAMP(0.0, params->max_delay_ratio, MAX_MAXDELAYRATIO);
+  result->max_delay_dev_ratio = CLAMP(0.0, params->max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
+  result->offset_correction = params->offset;
+  result->auto_burst = params->burst;
+  result->auto_offline = params->auto_offline;
+  result->poll_target = params->poll_target;
+
+  result->version = NTP_VERSION;
+
+  if (params->authkey == INACTIVE_AUTHKEY) {
+    result->auth_mode = AUTH_NONE;
+    result->auth_key_id = 0;
+  } else {
+    result->auth_mode = AUTH_SYMMETRIC;
+    result->auth_key_id = params->authkey;
+    if (!KEY_KeyKnown(result->auth_key_id)) {
+      LOG(LOGS_WARN, "Key %"PRIu32" used by source %s is %s",
+          result->auth_key_id, UTI_IPToString(&result->remote_addr.ip_addr),
+          "missing");
+    } else if (!KEY_CheckKeyLength(result->auth_key_id)) {
+      LOG(LOGS_WARN, "Key %"PRIu32" used by source %s is %s",
+          result->auth_key_id, UTI_IPToString(&result->remote_addr.ip_addr),
+          "too short");
+    }
+
+    /* If the MAC in NTPv4 packets would be truncated, use version 3 by
+       default for compatibility with older chronyd servers */
+    if (KEY_GetAuthLength(result->auth_key_id) + 4 > NTP_MAX_V4_MAC_LENGTH)
+      result->version = 3;
+  }
+
+  if (params->version)
+    result->version = CLAMP(NTP_MIN_COMPAT_VERSION, params->version, NTP_VERSION);
+
+  /* Create a source instance for this NTP source */
+  result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr),
+                                         SRC_NTP, params->sel_options,
+                                         &result->remote_addr.ip_addr,
+                                         params->min_samples, params->max_samples,
+                                         params->min_delay, params->asymmetry);
+
+  result->rx_timeout_id = 0;
+  result->tx_timeout_id = 0;
+  result->tx_suspended = 1;
+  result->opmode = params->online ? MD_ONLINE : MD_OFFLINE;
+  result->local_poll = result->minpoll;
+  result->poll_score = 0.0;
+  zero_local_timestamp(&result->local_tx);
+  result->burst_good_samples_to_go = 0;
+  result->burst_total_samples_to_go = 0;
+  memset(&result->report, 0, sizeof (result->report));
+  
+  NCR_ResetInstance(result);
+
+  if (params->iburst) {
+    NCR_InitiateSampleBurst(result, IBURST_GOOD_SAMPLES, IBURST_TOTAL_SAMPLES);
+  }
+
+  return result;
+}
+
+/* ================================================== */
+
+/* Destroy an instance */
+void
+NCR_DestroyInstance(NCR_Instance instance)
+{
+  if (instance->opmode != MD_OFFLINE)
+    take_offline(instance);
+
+  if (instance->mode == MODE_ACTIVE)
+    NIO_CloseServerSocket(instance->local_addr.sock_fd);
+
+  /* This will destroy the source instance inside the
+     structure, which will cause reselection if this was the
+     synchronising source etc. */
+  SRC_DestroyInstance(instance->source);
+
+  /* Free the data structure */
+  Free(instance);
+}
+
+/* ================================================== */
+
+void
+NCR_StartInstance(NCR_Instance instance)
+{
+  instance->tx_suspended = 0;
+  if (instance->opmode != MD_OFFLINE)
+    start_initial_timeout(instance);
+}
+
+/* ================================================== */
+
+void
+NCR_ResetInstance(NCR_Instance instance)
+{
+  instance->tx_count = 0;
+  instance->presend_done = 0;
+
+  instance->remote_poll = 0;
+  instance->remote_stratum = 0;
+
+  instance->valid_rx = 0;
+  instance->valid_timestamps = 0;
+  UTI_ZeroNtp64(&instance->remote_ntp_rx);
+  UTI_ZeroNtp64(&instance->remote_ntp_tx);
+  UTI_ZeroNtp64(&instance->local_ntp_rx);
+  UTI_ZeroNtp64(&instance->local_ntp_tx);
+  zero_local_timestamp(&instance->local_rx);
+
+  zero_local_timestamp(&instance->prev_local_tx);
+  instance->prev_local_poll = 0;
+  instance->prev_tx_count = 0;
+
+  instance->updated_init_timestamps = 0;
+  UTI_ZeroNtp64(&instance->init_remote_ntp_tx);
+  zero_local_timestamp(&instance->init_local_rx);
+}
+
+/* ================================================== */
+
+void
+NCR_ResetPoll(NCR_Instance instance)
+{
+  if (instance->local_poll != instance->minpoll) {
+    instance->local_poll = instance->minpoll;
+
+    /* The timer was set with a longer poll interval, restart it */
+    if (instance->tx_timeout_id)
+      restart_timeout(instance, get_transmit_delay(instance, 0, 0.0));
+  }
+}
+
+/* ================================================== */
+
+void
+NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr)
+{
+  memset(&inst->report, 0, sizeof (inst->report));
+  NCR_ResetInstance(inst);
+  inst->remote_addr = *remote_addr;
+
+  if (inst->mode == MODE_CLIENT)
+    close_client_socket(inst);
+  else {
+    NIO_CloseServerSocket(inst->local_addr.sock_fd);
+    inst->local_addr.ip_addr.family = IPADDR_UNSPEC;
+    inst->local_addr.if_index = INVALID_IF_INDEX;
+    inst->local_addr.sock_fd = NIO_OpenServerSocket(remote_addr);
+  }
+
+  /* Update the reference ID and reset the source/sourcestats instances */
+  SRC_SetRefid(inst->source, UTI_IPToRefid(&remote_addr->ip_addr),
+               &inst->remote_addr.ip_addr);
+  SRC_ResetInstance(inst->source);
+}
+
+/* ================================================== */
+
+static void
+adjust_poll(NCR_Instance inst, double adj)
+{
+  inst->poll_score += adj;
+
+  if (inst->poll_score >= 1.0) {
+    inst->local_poll += (int)inst->poll_score;
+    inst->poll_score -= (int)inst->poll_score;
+  }
+
+  if (inst->poll_score < 0.0) {
+    inst->local_poll += (int)(inst->poll_score - 1.0);
+    inst->poll_score -= (int)(inst->poll_score - 1.0);
+  }
+  
+  /* Clamp polling interval to defined range */
+  if (inst->local_poll < inst->minpoll) {
+    inst->local_poll = inst->minpoll;
+    inst->poll_score = 0;
+  } else if (inst->local_poll > inst->maxpoll) {
+    inst->local_poll = inst->maxpoll;
+    inst->poll_score = 1.0;
+  }
+}
+
+/* ================================================== */
+
+static double
+get_poll_adj(NCR_Instance inst, double error_in_estimate, double peer_distance)
+{
+  double poll_adj;
+  int samples;
+
+  if (error_in_estimate > peer_distance) {
+    poll_adj = -log(error_in_estimate / peer_distance) / log(2.0);
+  } else {
+    samples = SST_Samples(SRC_GetSourcestats(inst->source));
+
+    /* Adjust polling interval so that the number of sourcestats samples
+       remains close to the target value */
+    poll_adj = ((double)samples / inst->poll_target - 1.0) / inst->poll_target;
+
+    /* Make interval shortening quicker */
+    if (samples < inst->poll_target) {
+      poll_adj *= 2.0;
+    }
+  }
+
+  return poll_adj;
+}
+
+/* ================================================== */
+
+static int
+get_transmit_poll(NCR_Instance inst)
+{
+  int poll;
+
+  poll = inst->local_poll;
+
+  /* In symmetric mode, if the peer is responding, use shorter of the local
+     and remote poll interval, but not shorter than the minimum */
+  if (inst->mode == MODE_ACTIVE && poll > inst->remote_poll &&
+      inst->tx_count < MAX_PEER_POLL_TX)
+    poll = MAX(inst->remote_poll, inst->minpoll);
+
+  return poll;
+}
+
+/* ================================================== */
+
+static double
+get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
+{
+  int poll_to_use, stratum_diff;
+  double delay_time;
+
+  /* If we're in burst mode, queue for immediate dispatch.
+
+     If we're operating in client/server mode, queue the timeout for
+     the poll interval hence.  The fact that a timeout has been queued
+     in the transmit handler is immaterial - that is only done so that
+     we at least send something, if no reply is heard.
+
+     If we're in symmetric mode, we have to take account of the peer's
+     wishes, otherwise his sampling regime will fall to pieces.  If
+     we're in client/server mode, we don't care what poll interval the
+     server responded with last time. */
+
+  poll_to_use = get_transmit_poll(inst);
+  delay_time = UTI_Log2ToDouble(poll_to_use);
+
+  switch (inst->opmode) {
+    case MD_OFFLINE:
+      assert(0);
+      break;
+    case MD_ONLINE:
+      switch(inst->mode) {
+        case MODE_CLIENT:
+          if (inst->presend_done)
+            delay_time = WARM_UP_DELAY;
+          break;
+
+        case MODE_ACTIVE:
+          /* If the remote stratum is higher than ours, wait a bit for the next
+             packet before responding in order to minimize the delay of the
+             measurement and its error for the peer which has higher stratum.
+             If the remote stratum is equal to ours, try to interleave packets
+             evenly with the peer. */
+          stratum_diff = inst->remote_stratum - REF_GetOurStratum();
+          if ((stratum_diff > 0 && last_tx * PEER_SAMPLING_ADJ < delay_time) ||
+              (!on_tx && !stratum_diff &&
+               last_tx / delay_time > PEER_SAMPLING_ADJ - 0.5))
+            delay_time *= PEER_SAMPLING_ADJ;
+
+          /* Substract the already spend time */
+          if (last_tx > 0.0)
+            delay_time -= last_tx;
+          if (delay_time < 0.0)
+            delay_time = 0.0;
+
+          break;
+        default:
+          assert(0);
+          break;
+      }
+      break;
+
+    case MD_BURST_WAS_ONLINE:
+    case MD_BURST_WAS_OFFLINE:
+      /* Burst modes */
+      delay_time = on_tx ? BURST_TIMEOUT : BURST_INTERVAL;
+      break;
+    default:
+      assert(0);
+      break;
+  }
+
+  return delay_time;
+}
+
+/* ================================================== */
+/* Calculate sampling separation for given polling interval */
+
+static double
+get_separation(int poll)
+{
+  double separation;
+
+  /* Allow up to 8 sources using the same short interval to not be limited
+     by the separation */
+  separation = UTI_Log2ToDouble(poll - 3);
+
+  return CLAMP(MIN_SAMPLING_SEPARATION, separation, MAX_SAMPLING_SEPARATION);
+}
+
+/* ================================================== */
+/* Timeout handler for closing the client socket when no acceptable
+   reply can be received from the server */
+
+static void
+receive_timeout(void *arg)
+{
+  NCR_Instance inst = (NCR_Instance)arg;
+
+  DEBUG_LOG("Receive timeout for [%s:%d]",
+            UTI_IPToString(&inst->remote_addr.ip_addr), inst->remote_addr.port);
+
+  inst->rx_timeout_id = 0;
+  close_client_socket(inst);
+}
+
+/* ================================================== */
+
+static int
+transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
+                int interleaved, /* Flag enabling interleaved mode */
+                int my_poll, /* The log2 of the local poll interval */
+                int version, /* The NTP version to be set in the packet */
+                int auth_mode, /* The authentication mode */
+                uint32_t key_id, /* The authentication key ID */
+                NTP_int64 *remote_ntp_rx, /* The receive timestamp from received packet */
+                NTP_int64 *remote_ntp_tx, /* The transmit timestamp from received packet */
+                NTP_Local_Timestamp *local_rx, /* The RX time of the received packet */
+                NTP_Local_Timestamp *local_tx, /* The TX time of the previous packet
+                                                  RESULT : TX time of this packet */
+                NTP_int64 *local_ntp_rx, /* The receive timestamp from the previous packet
+                                            RESULT : receive timestamp from this packet */
+                NTP_int64 *local_ntp_tx, /* The transmit timestamp from the previous packet
+                                            RESULT : transmit timestamp from this packet */
+                NTP_Remote_Address *where_to, /* Where to address the reponse to */
+                NTP_Local_Address *from /* From what address to send it */
+                )
+{
+  NTP_Packet message;
+  int auth_len, mac_len, length, ret, precision;
+  struct timespec local_receive, local_transmit;
+  double smooth_offset, local_transmit_err;
+  NTP_int64 ts_fuzz;
+
+  /* Parameters read from reference module */
+  int are_we_synchronised, our_stratum, smooth_time;
+  NTP_Leap leap_status;
+  uint32_t our_ref_id;
+  struct timespec our_ref_time;
+  double our_root_delay, our_root_dispersion;
+
+  /* Don't reply with version higher than ours */
+  if (version > NTP_VERSION) {
+    version = NTP_VERSION;
+  }
+
+  /* Check if the packet can be formed in the interleaved mode */
+  if (interleaved && (!remote_ntp_rx || !local_tx || UTI_IsZeroTimespec(&local_tx->ts)))
+    interleaved = 0;
+
+  smooth_time = 0;
+  smooth_offset = 0.0;
+
+  if (my_mode == MODE_CLIENT) {
+    /* Don't reveal local time or state of the clock in client packets */
+    precision = 32;
+    leap_status = our_stratum = our_ref_id = 0;
+    our_root_delay = our_root_dispersion = 0.0;
+    UTI_ZeroTimespec(&our_ref_time);
+  } else {
+    /* This is accurate enough and cheaper than calling LCL_ReadCookedTime.
+       A more accurate timestamp will be taken later in this function. */
+    SCH_GetLastEventTime(&local_transmit, NULL, NULL);
+
+    REF_GetReferenceParams(&local_transmit,
+                           &are_we_synchronised, &leap_status,
+                           &our_stratum,
+                           &our_ref_id, &our_ref_time,
+                           &our_root_delay, &our_root_dispersion);
+
+    /* Get current smoothing offset when sending packet to a client */
+    if (SMT_IsEnabled() && (my_mode == MODE_SERVER || my_mode == MODE_BROADCAST)) {
+      smooth_offset = SMT_GetOffset(&local_transmit);
+      smooth_time = fabs(smooth_offset) > LCL_GetSysPrecisionAsQuantum();
+
+      /* Suppress leap second when smoothing and slew mode are enabled */
+      if (REF_GetLeapMode() == REF_LeapModeSlew &&
+          (leap_status == LEAP_InsertSecond || leap_status == LEAP_DeleteSecond))
+        leap_status = LEAP_Normal;
+    }
+
+    precision = LCL_GetSysPrecisionAsLog();
+  }
+
+  if (smooth_time && !UTI_IsZeroTimespec(&local_rx->ts)) {
+    our_ref_id = NTP_REFID_SMOOTH;
+    UTI_AddDoubleToTimespec(&our_ref_time, smooth_offset, &our_ref_time);
+    UTI_AddDoubleToTimespec(&local_rx->ts, smooth_offset, &local_receive);
+  } else {
+    local_receive = local_rx->ts;
+  }
+
+  /* Generate transmit packet */
+  message.lvm = NTP_LVM(leap_status, version, my_mode);
+  /* Stratum 16 and larger are invalid */
+  if (our_stratum < NTP_MAX_STRATUM) {
+    message.stratum = our_stratum;
+  } else {
+    message.stratum = NTP_INVALID_STRATUM;
+  }
+ 
+  message.poll = my_poll;
+  message.precision = precision;
+
+  /* If we're sending a client mode packet and we aren't synchronized yet, 
+     we might have to set up artificial values for some of these parameters */
+  message.root_delay = UTI_DoubleToNtp32(our_root_delay);
+  message.root_dispersion = UTI_DoubleToNtp32(our_root_dispersion);
+
+  message.reference_id = htonl(our_ref_id);
+
+  /* Now fill in timestamps */
+
+  UTI_TimespecToNtp64(&our_ref_time, &message.reference_ts, NULL);
+
+  /* Don't reveal timestamps which are not necessary for the protocol */
+
+  if (my_mode != MODE_CLIENT || interleaved) {
+    /* Originate - this comes from the last packet the source sent us */
+    message.originate_ts = interleaved ? *remote_ntp_rx : *remote_ntp_tx;
+
+    do {
+      /* Prepare random bits which will be added to the receive timestamp */
+      UTI_GetNtp64Fuzz(&ts_fuzz, precision);
+
+      /* Receive - this is when we received the last packet from the source.
+         This timestamp will have been adjusted so that it will now look to
+         the source like we have been running on our latest estimate of
+         frequency all along */
+      UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz);
+
+      /* Do not send a packet with a non-zero receive timestamp equal to the
+         originate timestamp or previous receive timestamp */
+    } while (!UTI_IsZeroNtp64(&message.receive_ts) &&
+             UTI_IsEqualAnyNtp64(&message.receive_ts, &message.originate_ts,
+                                 local_ntp_rx, NULL));
+  } else {
+    UTI_ZeroNtp64(&message.originate_ts);
+    UTI_ZeroNtp64(&message.receive_ts);
+  }
+
+  do {
+    /* Prepare random bits which will be added to the transmit timestamp */
+    UTI_GetNtp64Fuzz(&ts_fuzz, precision);
+
+    /* Transmit - this our local time right now!  Also, we might need to
+       store this for our own use later, next time we receive a message
+       from the source we're sending to now. */
+    LCL_ReadCookedTime(&local_transmit, &local_transmit_err);
+
+    if (smooth_time)
+      UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
+
+    length = NTP_NORMAL_PACKET_LENGTH;
+
+    /* Authenticate the packet */
+
+    if (auth_mode == AUTH_SYMMETRIC || auth_mode == AUTH_MSSNTP) {
+      /* Pre-compensate the transmit time by approximately how long it will
+         take to generate the authentication data */
+      local_transmit.tv_nsec += auth_mode == AUTH_SYMMETRIC ?
+                                KEY_GetAuthDelay(key_id) : NSD_GetAuthDelay(key_id);
+      UTI_NormaliseTimespec(&local_transmit);
+      UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
+                          &message.transmit_ts, &ts_fuzz);
+
+      if (auth_mode == AUTH_SYMMETRIC) {
+        auth_len = KEY_GenerateAuth(key_id, (unsigned char *) &message,
+                                    offsetof(NTP_Packet, auth_keyid),
+                                    (unsigned char *)&message.auth_data,
+                                    sizeof (message.auth_data));
+        if (!auth_len) {
+          DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
+          return 0;
+        }
+
+        message.auth_keyid = htonl(key_id);
+        mac_len = sizeof (message.auth_keyid) + auth_len;
+
+        /* Truncate MACs in NTPv4 packets to allow deterministic parsing
+           of extension fields (RFC 7822) */
+        if (version == 4 && mac_len > NTP_MAX_V4_MAC_LENGTH)
+          mac_len = NTP_MAX_V4_MAC_LENGTH;
+
+        length += mac_len;
+      } else if (auth_mode == AUTH_MSSNTP) {
+        /* MS-SNTP packets are signed (asynchronously) by ntp_signd */
+        return NSD_SignAndSendPacket(key_id, &message, where_to, from, length);
+      }
+    } else {
+      UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
+                          &message.transmit_ts, &ts_fuzz);
+    }
+
+    /* Do not send a packet with a non-zero transmit timestamp which is
+       equal to any of the following timestamps:
+       - receive (to allow reliable detection of the interleaved mode)
+       - originate (to prevent the packet from being its own valid response
+                    in the symmetric mode)
+       - previous transmit (to invalidate responses to the previous packet)
+       (the precision must be at least -30 to prevent an infinite loop!) */
+  } while (!UTI_IsZeroNtp64(&message.transmit_ts) &&
+           UTI_IsEqualAnyNtp64(&message.transmit_ts, &message.receive_ts,
+                               &message.originate_ts, local_ntp_tx));
+
+  ret = NIO_SendPacket(&message, where_to, from, length, local_tx != NULL);
+
+  if (local_tx) {
+    local_tx->ts = local_transmit;
+    local_tx->err = local_transmit_err;
+    local_tx->source = NTP_TS_DAEMON;
+  }
+
+  if (local_ntp_rx)
+    *local_ntp_rx = message.receive_ts;
+  if (local_ntp_tx)
+    *local_ntp_tx = message.transmit_ts;
+
+  return ret;
+}
+
+/* ================================================== */
+/* Timeout handler for transmitting to a source. */
+
+static void
+transmit_timeout(void *arg)
+{
+  NCR_Instance inst = (NCR_Instance) arg;
+  NTP_Local_Address local_addr;
+  int interleaved, initial, sent;
+
+  inst->tx_timeout_id = 0;
+
+  switch (inst->opmode) {
+    case MD_BURST_WAS_ONLINE:
+      /* With online burst switch to online before last packet */
+      if (inst->burst_total_samples_to_go <= 1)
+        inst->opmode = MD_ONLINE;
+      break;
+    case MD_BURST_WAS_OFFLINE:
+      if (inst->burst_total_samples_to_go <= 0)
+        take_offline(inst);
+      break;
+    case MD_ONLINE:
+      /* Start a new burst if the burst option is enabled and the average
+         polling interval including the burst will not fall below the
+         minimum polling interval */
+      if (inst->auto_burst && inst->local_poll > inst->minpoll && inst->local_poll > 1)
+        NCR_InitiateSampleBurst(inst, BURST_GOOD_SAMPLES,
+                                MIN(1 << (inst->local_poll - inst->minpoll),
+                                    MAX_BURST_TOTAL_SAMPLES));
+      break;
+    default:
+      break;
+  }
+
+  /* With auto_offline take the source offline on 2nd missed reply */
+  if (inst->auto_offline && inst->tx_count >= 2)
+    NCR_TakeSourceOffline(inst);
+
+  if (inst->opmode == MD_OFFLINE) {
+    return;
+  }
+
+  DEBUG_LOG("Transmit timeout for [%s:%d]",
+      UTI_IPToString(&inst->remote_addr.ip_addr), inst->remote_addr.port);
+
+  /* Open new client socket */
+  if (inst->mode == MODE_CLIENT) {
+    close_client_socket(inst);
+    assert(inst->local_addr.sock_fd == INVALID_SOCK_FD);
+    inst->local_addr.sock_fd = NIO_OpenClientSocket(&inst->remote_addr);
+  }
+
+  /* Don't require the packet to be sent from the same address as before */
+  local_addr.ip_addr.family = IPADDR_UNSPEC;
+  local_addr.if_index = INVALID_IF_INDEX;
+  local_addr.sock_fd = inst->local_addr.sock_fd;
+
+  /* In symmetric mode, don't send a packet in interleaved mode unless it
+     is the first response to the last valid request received from the peer
+     and there was just one response to the previous valid request.  This
+     prevents the peer from matching the transmit timestamp with an older
+     response if it can't detect missed responses.  In client mode, which has
+     at most one response per request, check how many responses are missing to
+     prevent the server from responding with a very old transmit timestamp. */
+  interleaved = inst->interleaved &&
+                ((inst->mode == MODE_CLIENT &&
+                  inst->tx_count < MAX_CLIENT_INTERLEAVED_TX) ||
+                 (inst->mode == MODE_ACTIVE &&
+                  inst->prev_tx_count == 1 && inst->tx_count == 0));
+
+  /* In symmetric mode, if no valid response was received since the previous
+     transmission, respond to the last received packet even if it failed some
+     specific NTP tests.  This is necessary for starting and restarting the
+     protocol, e.g. when a packet was lost. */
+  initial = inst->mode == MODE_ACTIVE && !inst->valid_rx &&
+            !UTI_IsZeroNtp64(&inst->init_remote_ntp_tx);
+
+  /* Prepare for the response */
+  inst->valid_rx = 0;
+  inst->updated_init_timestamps = 0;
+  if (initial)
+    inst->valid_timestamps = 0;
+
+  /* Check whether we need to 'warm up' the link to the other end by
+     sending an NTP exchange to ensure both ends' ARP caches are
+     primed or whether we need to send two packets first to ensure a
+     server in the interleaved mode has a fresh timestamp for us. */
+  if (inst->presend_minpoll <= inst->local_poll && !inst->presend_done &&
+      !inst->burst_total_samples_to_go) {
+    inst->presend_done = interleaved ? 2 : 1;
+  } else if (inst->presend_done > 0) {
+    inst->presend_done--;
+  }
+
+  /* Send the request (which may also be a response in the symmetric mode) */
+  sent = transmit_packet(inst->mode, interleaved, inst->local_poll, inst->version,
+                         inst->auth_mode, inst->auth_key_id,
+                         initial ? NULL : &inst->remote_ntp_rx,
+                         initial ? &inst->init_remote_ntp_tx : &inst->remote_ntp_tx,
+                         initial ? &inst->init_local_rx : &inst->local_rx,
+                         &inst->local_tx, &inst->local_ntp_rx, &inst->local_ntp_tx,
+                         &inst->remote_addr, &local_addr);
+
+  ++inst->tx_count;
+  if (sent)
+    inst->report.total_tx_count++;
+
+  /* If the source loses connectivity and our packets are still being sent,
+     back off the sampling rate to reduce the network traffic.  If it's the
+     source to which we are currently locked, back off slowly. */
+
+  if (inst->tx_count >= 2) {
+    /* Implies we have missed at least one transmission */
+
+    if (sent) {
+      adjust_poll(inst, SRC_IsSyncPeer(inst->source) ? 0.1 : 0.25);
+    }
+
+    SRC_UpdateReachability(inst->source, 0);
+  }
+
+  switch (inst->opmode) {
+    case MD_BURST_WAS_ONLINE:
+      /* When not reachable, don't stop online burst until sending succeeds */
+      if (!sent && !SRC_IsReachable(inst->source))
+        break;
+      /* Fall through */
+    case MD_BURST_WAS_OFFLINE:
+      --inst->burst_total_samples_to_go;
+      break;
+    default:
+      break;
+  }
+
+  /* Restart timer for this message */
+  restart_timeout(inst, get_transmit_delay(inst, 1, 0.0));
+
+  /* If a client packet was just sent, schedule a timeout to close the socket
+     at the time when all server replies would fail the delay test, so the
+     socket is not open for longer than necessary */
+  if (inst->mode == MODE_CLIENT)
+    inst->rx_timeout_id = SCH_AddTimeoutByDelay(inst->max_delay + MAX_SERVER_INTERVAL,
+                                                receive_timeout, (void *)inst);
+}
+
+/* ================================================== */
+
+static int
+check_packet_format(NTP_Packet *message, int length)
+{
+  int version;
+
+  /* Check version and length */
+
+  version = NTP_LVM_TO_VERSION(message->lvm);
+  if (version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) {
+    DEBUG_LOG("NTP packet has invalid version %d", version);
+    return 0;
+  } 
+
+  if (length < NTP_NORMAL_PACKET_LENGTH || (unsigned int)length % 4) {
+    DEBUG_LOG("NTP packet has invalid length %d", length);
+    return 0;
+  }
+
+  /* We can't reliably check the packet for invalid extension fields as we
+     support MACs longer than the shortest valid extension field */
+
+  return 1;
+}
+
+/* ================================================== */
+
+static int
+is_zero_data(unsigned char *data, int length)
+{
+  int i;
+
+  for (i = 0; i < length; i++)
+    if (data[i])
+      return 0;
+  return 1;
+}
+
+/* ================================================== */
+
+static int
+check_packet_auth(NTP_Packet *pkt, int length,
+                  AuthenticationMode *auth_mode, uint32_t *key_id)
+{
+  int i, version, remainder, ext_length, max_mac_length;
+  unsigned char *data;
+  uint32_t id;
+
+  /* Go through extension fields and see if there is a valid MAC */
+
+  version = NTP_LVM_TO_VERSION(pkt->lvm);
+  i = NTP_NORMAL_PACKET_LENGTH;
+  data = (void *)pkt;
+
+  while (1) {
+    remainder = length - i;
+
+    /* Check if the remaining data is a valid MAC.  There is a limit on MAC
+       length in NTPv4 packets to allow deterministic parsing of extension
+       fields (RFC 7822), but we need to support longer MACs to not break
+       compatibility with older chrony clients.  This needs to be done before
+       trying to parse the data as an extension field. */
+
+    max_mac_length = version == 4 && remainder <= NTP_MAX_V4_MAC_LENGTH ?
+                     NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH;
+
+    if (remainder >= NTP_MIN_MAC_LENGTH && remainder <= max_mac_length) {
+      id = ntohl(*(uint32_t *)(data + i));
+      if (KEY_CheckAuth(id, (void *)pkt, i, (void *)(data + i + 4),
+                        remainder - 4, max_mac_length - 4)) {
+        *auth_mode = AUTH_SYMMETRIC;
+        *key_id = id;
+
+        /* If it's an NTPv4 packet with long MAC and no extension fields,
+           rewrite the version in the packet to respond with long MAC too */
+        if (version == 4 && NTP_NORMAL_PACKET_LENGTH + remainder == length &&
+            remainder > NTP_MAX_V4_MAC_LENGTH)
+          pkt->lvm = NTP_LVM(NTP_LVM_TO_LEAP(pkt->lvm), 3, NTP_LVM_TO_MODE(pkt->lvm));
+
+        return 1;
+      }
+    }
+
+    /* Check if this is a valid NTPv4 extension field and skip it.  It should
+       have a 16-bit type, 16-bit length, and data padded to 32 bits. */
+    if (version == 4 && remainder >= NTP_MIN_EXTENSION_LENGTH) {
+      ext_length = ntohs(*(uint16_t *)(data + i + 2));
+      if (ext_length >= NTP_MIN_EXTENSION_LENGTH &&
+          ext_length <= remainder && ext_length % 4 == 0) {
+        i += ext_length;
+        continue;
+      }
+    }
+
+    /* Invalid or missing MAC, or format error */
+    break;
+  }
+
+  /* This is not 100% reliable as a MAC could fail to authenticate and could
+     pass as an extension field, leaving reminder smaller than the minimum MAC
+     length */
+  if (remainder >= NTP_MIN_MAC_LENGTH) {
+    *auth_mode = AUTH_SYMMETRIC;
+    *key_id = ntohl(*(uint32_t *)(data + i));
+
+    /* Check if it is an MS-SNTP authenticator field or extended authenticator
+       field with zeroes as digest */
+    if (version == 3 && *key_id) {
+      if (remainder == 20 && is_zero_data(data + i + 4, remainder - 4))
+        *auth_mode = AUTH_MSSNTP;
+      else if (remainder == 72 && is_zero_data(data + i + 8, remainder - 8))
+        *auth_mode = AUTH_MSSNTP_EXT;
+    }
+  } else {
+    *auth_mode = AUTH_NONE;
+    *key_id = 0;
+  }
+
+  return 0;
+}
+
+/* ================================================== */
+
+static int
+check_delay_ratio(NCR_Instance inst, SST_Stats stats,
+                struct timespec *sample_time, double delay)
+{
+  double last_sample_ago, predicted_offset, min_delay, skew, std_dev;
+  double max_delay;
+
+  if (inst->max_delay_ratio < 1.0 ||
+      !SST_GetDelayTestData(stats, sample_time, &last_sample_ago,
+                            &predicted_offset, &min_delay, &skew, &std_dev))
+    return 1;
+
+  max_delay = min_delay * inst->max_delay_ratio +
+              last_sample_ago * (skew + LCL_GetMaxClockError());
+
+  if (delay <= max_delay)
+    return 1;
+
+  DEBUG_LOG("maxdelayratio: delay=%e max_delay=%e", delay, max_delay);
+  return 0;
+}
+
+/* ================================================== */
+
+static int
+check_delay_dev_ratio(NCR_Instance inst, SST_Stats stats,
+                      struct timespec *sample_time, double offset, double delay)
+{
+  double last_sample_ago, predicted_offset, min_delay, skew, std_dev;
+  double delta, max_delta, error_in_estimate;
+
+  if (!SST_GetDelayTestData(stats, sample_time, &last_sample_ago,
+                            &predicted_offset, &min_delay, &skew, &std_dev))
+    return 1;
+
+  /* Require that the ratio of the increase in delay from the minimum to the
+     standard deviation is less than max_delay_dev_ratio.  In the allowed
+     increase in delay include also dispersion. */
+
+  max_delta = std_dev * inst->max_delay_dev_ratio +
+              last_sample_ago * (skew + LCL_GetMaxClockError());
+  delta = (delay - min_delay) / 2.0;
+
+  if (delta <= max_delta)
+    return 1;
+
+  error_in_estimate = offset + predicted_offset;
+
+  /* Before we decide to drop the sample, make sure the difference between
+     measured offset and predicted offset is not significantly larger than
+     the increase in delay */
+  if (fabs(error_in_estimate) - delta > max_delta)
+    return 1;
+
+  DEBUG_LOG("maxdelaydevratio: error=%e delay=%e delta=%e max_delta=%e",
+            error_in_estimate, delay, delta, max_delta);
+  return 0;
+}
+
+/* ================================================== */
+
+static int
+receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
+               NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
+{
+  SST_Stats stats;
+
+  int pkt_leap, pkt_version;
+  uint32_t pkt_refid, pkt_key_id;
+  double pkt_root_delay;
+  double pkt_root_dispersion;
+  AuthenticationMode pkt_auth_mode;
+
+  /* The local time to which the (offset, delay, dispersion) triple will
+     be taken to relate.  For client/server operation this is practically
+     the same as either the transmit or receive time.  The difference comes
+     in symmetric active mode, when the receive may come minutes after the
+     transmit, and this time will be midway between the two */
+  struct timespec sample_time;
+
+  /* The estimated offset in seconds, a positive value indicates that the local
+     clock is SLOW of the remote source and a negative value indicates that the
+     local clock is FAST of the remote source */
+  double offset;
+
+  /* The estimated peer delay, dispersion and distance */
+  double delay, dispersion, distance;
+
+  /* The total root delay and dispersion */
+  double root_delay, root_dispersion;
+
+  /* The skew and estimated frequency offset relative to the remote source */
+  double skew, source_freq_lo, source_freq_hi;
+
+  /* RFC 5905 packet tests */
+  int test1, test2n, test2i, test2, test3, test5, test6, test7;
+  int interleaved_packet, valid_packet, synced_packet;
+
+  /* Additional tests */
+  int testA, testB, testC, testD;
+  int good_packet;
+
+  /* Kiss-o'-Death codes */
+  int kod_rate;
+
+  /* The estimated offset predicted from previous samples.  The
+     convention here is that positive means local clock FAST of
+     reference, i.e. backwards to the way that 'offset' is defined. */
+  double estimated_offset;
+
+  /* The absolute difference between the offset estimate and
+     measurement in seconds */
+  double error_in_estimate;
+
+  NTP_Local_Timestamp local_receive, local_transmit;
+  double remote_interval, local_interval, response_time;
+  double delay_time, precision;
+  int updated_timestamps;
+
+  /* ==================== */
+
+  stats = SRC_GetSourcestats(inst->source);
+
+  inst->report.total_rx_count++;
+
+  pkt_leap = NTP_LVM_TO_LEAP(message->lvm);
+  pkt_version = NTP_LVM_TO_VERSION(message->lvm);
+  pkt_refid = ntohl(message->reference_id);
+  pkt_root_delay = UTI_Ntp32ToDouble(message->root_delay);
+  pkt_root_dispersion = UTI_Ntp32ToDouble(message->root_dispersion);
+
+  /* Check if the packet is valid per RFC 5905, section 8.
+     The test values are 1 when passed and 0 when failed. */
+  
+  /* Test 1 checks for duplicate packet */
+  test1 = UTI_CompareNtp64(&message->receive_ts, &inst->remote_ntp_rx) ||
+          UTI_CompareNtp64(&message->transmit_ts, &inst->remote_ntp_tx);
+
+  /* Test 2 checks for bogus packet in the basic and interleaved modes.  This
+     ensures the source is responding to the latest packet we sent to it. */
+  test2n = !UTI_CompareNtp64(&message->originate_ts, &inst->local_ntp_tx);
+  test2i = inst->interleaved &&
+           !UTI_CompareNtp64(&message->originate_ts, &inst->local_ntp_rx);
+  test2 = test2n || test2i;
+  interleaved_packet = !test2n && test2i;
+  
+  /* Test 3 checks for invalid timestamps.  This can happen when the
+     association if not properly 'up'. */
+  test3 = !UTI_IsZeroNtp64(&message->originate_ts) &&
+          !UTI_IsZeroNtp64(&message->receive_ts) &&
+          !UTI_IsZeroNtp64(&message->transmit_ts);
+
+  /* Test 4 would check for denied access.  It would always pass as this
+     function is called only for known sources. */
+
+  /* Test 5 checks for authentication failure.  If we expect authenticated info
+     from this peer/server and the packet doesn't have it, the authentication
+     is bad, or it's authenticated with a different key than expected, it's got
+     to fail.  If we don't expect the packet to be authenticated, just ignore
+     the test. */
+  test5 = inst->auth_mode == AUTH_NONE ||
+          (check_packet_auth(message, length, &pkt_auth_mode, &pkt_key_id) &&
+           pkt_auth_mode == inst->auth_mode && pkt_key_id == inst->auth_key_id);
+
+  /* Test 6 checks for unsynchronised server */
+  test6 = pkt_leap != LEAP_Unsynchronised &&
+          message->stratum < NTP_MAX_STRATUM &&
+          message->stratum != NTP_INVALID_STRATUM; 
+
+  /* Test 7 checks for bad data.  The root distance must be smaller than a
+     defined maximum. */
+  test7 = pkt_root_delay / 2.0 + pkt_root_dispersion < NTP_MAX_DISPERSION;
+
+  /* The packet is considered valid if the tests 1-5 passed.  The timestamps
+     can be used for synchronisation if the tests 6 and 7 passed too. */
+  valid_packet = test1 && test2 && test3 && test5;
+  synced_packet = valid_packet && test6 && test7;
+
+  /* Check for Kiss-o'-Death codes */
+  kod_rate = 0;
+  if (test1 && test2 && test5 && pkt_leap == LEAP_Unsynchronised &&
+      message->stratum == NTP_INVALID_STRATUM) {
+    if (pkt_refid == KOD_RATE)
+      kod_rate = 1;
+  }
+
+  if (synced_packet && (!interleaved_packet || inst->valid_timestamps)) {
+    /* These are the timespec equivalents of the remote and local epochs */
+    struct timespec remote_receive, remote_transmit, remote_request_receive;
+    struct timespec local_average, remote_average, prev_remote_transmit;
+    double prev_remote_poll_interval;
+
+    /* Select remote and local timestamps for the new sample */
+    if (interleaved_packet) {
+      /* Prefer previous local TX and remote RX timestamps if it will make
+         the intervals significantly shorter in order to improve the accuracy
+         of the measured delay */
+      if (!UTI_IsZeroTimespec(&inst->prev_local_tx.ts) &&
+          MAX_INTERLEAVED_L2L_RATIO *
+            UTI_DiffTimespecsToDouble(&inst->local_tx.ts, &inst->local_rx.ts) >
+          UTI_DiffTimespecsToDouble(&inst->local_rx.ts, &inst->prev_local_tx.ts)) {
+        UTI_Ntp64ToTimespec(&inst->remote_ntp_rx, &remote_receive);
+        remote_request_receive = remote_receive;
+        local_transmit = inst->prev_local_tx;
+      } else {
+        UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
+        UTI_Ntp64ToTimespec(&inst->remote_ntp_rx, &remote_request_receive);
+        local_transmit = inst->local_tx;
+      }
+      UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
+      UTI_Ntp64ToTimespec(&inst->remote_ntp_tx, &prev_remote_transmit);
+      local_receive = inst->local_rx;
+    } else {
+      UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
+      UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
+      UTI_ZeroTimespec(&prev_remote_transmit);
+      remote_request_receive = remote_receive;
+      local_receive = *rx_ts;
+      local_transmit = inst->local_tx;
+    }
+
+    /* Calculate intervals between remote and local timestamps */
+    UTI_AverageDiffTimespecs(&remote_receive, &remote_transmit,
+                             &remote_average, &remote_interval);
+    UTI_AverageDiffTimespecs(&local_transmit.ts, &local_receive.ts,
+                             &local_average, &local_interval);
+    response_time = fabs(UTI_DiffTimespecsToDouble(&remote_transmit,
+                                                   &remote_request_receive));
+
+    precision = LCL_GetSysPrecisionAsQuantum() + UTI_Log2ToDouble(message->precision);
+
+    /* Calculate delay */
+    delay = fabs(local_interval - remote_interval);
+    if (delay < precision)
+      delay = precision;
+    
+    /* Calculate offset.  Following the NTP definition, this is negative
+       if we are fast of the remote source. */
+    offset = UTI_DiffTimespecsToDouble(&remote_average, &local_average);
+
+    /* Apply configured correction */
+    offset += inst->offset_correction;
+
+    /* We treat the time of the sample as being midway through the local
+       measurement period.  An analysis assuming constant relative
+       frequency and zero network delay shows this is the only possible
+       choice to estimate the frequency difference correctly for every
+       sample pair. */
+    sample_time = local_average;
+    
+    SST_GetFrequencyRange(stats, &source_freq_lo, &source_freq_hi);
+
+    /* Calculate skew */
+    skew = (source_freq_hi - source_freq_lo) / 2.0;
+    
+    /* and then calculate peer dispersion */
+    dispersion = MAX(precision, MAX(local_transmit.err, local_receive.err)) +
+                 skew * fabs(local_interval);
+    
+    /* If the source is an active peer, this is the minimum assumed interval
+       between previous two transmissions (if not constrained by minpoll) */
+    prev_remote_poll_interval = UTI_Log2ToDouble(MIN(inst->remote_poll,
+                                                     inst->prev_local_poll));
+
+    /* Additional tests required to pass before accumulating the sample */
+
+    /* Test A requires that the minimum estimate of the peer delay is not
+       larger than the configured maximum, in both client modes that the server
+       processing time is sane, and in interleaved symmetric mode that the
+       measured delay and intervals between remote timestamps don't indicate
+       a missed response */
+    testA = delay - dispersion <= inst->max_delay && precision <= inst->max_delay &&
+            !(inst->mode == MODE_CLIENT && response_time > MAX_SERVER_INTERVAL) &&
+            !(inst->mode == MODE_ACTIVE && interleaved_packet &&
+              (delay > 0.5 * prev_remote_poll_interval ||
+               UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts) <= 0 ||
+               (inst->remote_poll <= inst->prev_local_poll &&
+                UTI_DiffTimespecsToDouble(&remote_transmit, &prev_remote_transmit) >
+                  1.5 * prev_remote_poll_interval)));
+
+    /* Test B requires in client mode that the ratio of the round trip delay
+       to the minimum one currently in the stats data register is less than an
+       administrator-defined value */
+    testB = check_delay_ratio(inst, stats, &sample_time, delay);
+
+    /* Test C requires that the ratio of the increase in delay from the minimum
+       one in the stats data register to the standard deviation of the offsets
+       in the register is less than an administrator-defined value or the
+       difference between measured offset and predicted offset is larger than
+       the increase in delay */
+    testC = check_delay_dev_ratio(inst, stats, &sample_time, offset, delay);
+
+    /* Test D requires that the remote peer is not synchronised to us to
+       prevent a synchronisation loop */
+    testD = message->stratum <= 1 || REF_GetMode() != REF_ModeNormal ||
+            pkt_refid != UTI_IPToRefid(&local_addr->ip_addr);
+  } else {
+    remote_interval = local_interval = response_time = 0.0;
+    offset = delay = dispersion = 0.0;
+    sample_time = rx_ts->ts;
+    local_receive = *rx_ts;
+    local_transmit = inst->local_tx;
+    testA = testB = testC = testD = 0;
+  }
+  
+  /* The packet is considered good for synchronisation if
+     the additional tests passed */
+  good_packet = testA && testB && testC && testD;
+
+  root_delay = pkt_root_delay + delay;
+  root_dispersion = pkt_root_dispersion + dispersion;
+  distance = dispersion + 0.5 * delay;
+
+  /* Update the NTP timestamps.  If it's a valid packet from a synchronised
+     source, the timestamps may be used later when processing a packet in the
+     interleaved mode.  Protect the timestamps against replay attacks in client
+     mode, and also in symmetric mode as long as the peers use the same polling
+     interval and never start with clocks in future or very distant past.
+     The authentication test (test5) is required to prevent DoS attacks using
+     unauthenticated packets on authenticated symmetric associations. */
+  if ((inst->mode == MODE_CLIENT && valid_packet && !inst->valid_rx) ||
+      (inst->mode == MODE_ACTIVE && valid_packet &&
+       (!inst->valid_rx ||
+        UTI_CompareNtp64(&inst->remote_ntp_tx, &message->transmit_ts) < 0))) {
+    inst->remote_ntp_rx = message->receive_ts;
+    inst->remote_ntp_tx = message->transmit_ts;
+    inst->local_rx = *rx_ts;
+    inst->valid_timestamps = synced_packet;
+
+    UTI_ZeroNtp64(&inst->init_remote_ntp_tx);
+    zero_local_timestamp(&inst->init_local_rx);
+    inst->updated_init_timestamps = 0;
+    updated_timestamps = 2;
+
+    /* Don't use the same set of timestamps for the next sample */
+    if (interleaved_packet)
+      inst->prev_local_tx = inst->local_tx;
+    else
+      zero_local_timestamp(&inst->prev_local_tx);
+  } else if (inst->mode == MODE_ACTIVE &&
+             test1 && !UTI_IsZeroNtp64(&message->transmit_ts) && test5 &&
+             (!inst->updated_init_timestamps ||
+              UTI_CompareNtp64(&inst->init_remote_ntp_tx, &message->transmit_ts) < 0)) {
+    inst->init_remote_ntp_tx = message->transmit_ts;
+    inst->init_local_rx = *rx_ts;
+    inst->updated_init_timestamps = 1;
+    updated_timestamps = 1;
+  } else {
+    updated_timestamps = 0;
+  }
+
+  /* Accept at most one response per request.  The NTP specification recommends
+     resetting local_ntp_tx to make the following packets fail test2 or test3,
+     but that would not allow the code above to make multiple updates of the
+     timestamps in symmetric mode.  Also, ignore presend responses. */
+  if (inst->valid_rx) {
+    test2 = test3 = 0;
+    valid_packet = synced_packet = good_packet = 0;
+  } else if (valid_packet) {
+    if (inst->presend_done) {
+      testA = 0;
+      good_packet = 0;
+    }
+    inst->valid_rx = 1;
+  }
+
+  if ((unsigned int)local_receive.source >= sizeof (tss_chars) ||
+      (unsigned int)local_transmit.source >= sizeof (tss_chars))
+    assert(0);
+
+  DEBUG_LOG("NTP packet lvm=%o stratum=%d poll=%d prec=%d root_delay=%f root_disp=%f refid=%"PRIx32" [%s]",
+            message->lvm, message->stratum, message->poll, message->precision,
+            pkt_root_delay, pkt_root_dispersion, pkt_refid,
+            message->stratum == NTP_INVALID_STRATUM ? UTI_RefidToString(pkt_refid) : "");
+  DEBUG_LOG("reference=%s origin=%s receive=%s transmit=%s",
+            UTI_Ntp64ToString(&message->reference_ts),
+            UTI_Ntp64ToString(&message->originate_ts),
+            UTI_Ntp64ToString(&message->receive_ts),
+            UTI_Ntp64ToString(&message->transmit_ts));
+  DEBUG_LOG("offset=%.9f delay=%.9f dispersion=%f root_delay=%f root_dispersion=%f",
+            offset, delay, dispersion, root_delay, root_dispersion);
+  DEBUG_LOG("remote_interval=%.9f local_interval=%.9f response_time=%.9f txs=%c rxs=%c",
+            remote_interval, local_interval, response_time,
+            tss_chars[local_transmit.source], tss_chars[local_receive.source]);
+  DEBUG_LOG("test123=%d%d%d test567=%d%d%d testABCD=%d%d%d%d kod_rate=%d interleaved=%d"
+            " presend=%d valid=%d good=%d updated=%d",
+            test1, test2, test3, test5, test6, test7, testA, testB, testC, testD,
+            kod_rate, interleaved_packet, inst->presend_done, valid_packet, good_packet,
+            updated_timestamps);
+
+  if (valid_packet) {
+    inst->remote_poll = message->poll;
+    inst->remote_stratum = message->stratum != NTP_INVALID_STRATUM ?
+                           message->stratum : NTP_MAX_STRATUM;
+
+    inst->prev_local_poll = inst->local_poll;
+    inst->prev_tx_count = inst->tx_count;
+    inst->tx_count = 0;
+
+    SRC_UpdateReachability(inst->source, synced_packet);
+
+    if (good_packet) {
+      /* Do this before we accumulate a new sample into the stats registers, obviously */
+      estimated_offset = SST_PredictOffset(stats, &sample_time);
+
+      SRC_AccumulateSample(inst->source,
+                           &sample_time,
+                           offset, delay, dispersion,
+                           root_delay, root_dispersion,
+                           MAX(message->stratum, inst->min_stratum),
+                           (NTP_Leap) pkt_leap);
+
+      SRC_SelectSource(inst->source);
+
+      /* Now examine the registers.  First though, if the prediction is
+         not even within +/- the peer distance of the peer, we are clearly
+         not tracking the peer at all well, so we back off the sampling
+         rate depending on just how bad the situation is. */
+      error_in_estimate = fabs(-offset - estimated_offset);
+
+      /* Now update the polling interval */
+      adjust_poll(inst, get_poll_adj(inst, error_in_estimate, distance));
+
+      /* If we're in burst mode, check whether the burst is completed and
+         revert to the previous mode */
+      switch (inst->opmode) {
+        case MD_BURST_WAS_ONLINE:
+        case MD_BURST_WAS_OFFLINE:
+          --inst->burst_good_samples_to_go;
+          if (inst->burst_good_samples_to_go <= 0) {
+            if (inst->opmode == MD_BURST_WAS_ONLINE)
+              inst->opmode = MD_ONLINE;
+            else
+              take_offline(inst);
+          }
+          break;
+        default:
+          break;
+      }
+    } else {
+      /* Slowly increase the polling interval if we can't get good packet */
+      adjust_poll(inst, 0.1);
+    }
+
+    /* If in client mode, no more packets are expected to be coming from the
+       server and the socket can be closed */
+    close_client_socket(inst);
+
+    /* Update the local address and interface */
+    inst->local_addr.ip_addr = local_addr->ip_addr;
+    inst->local_addr.if_index = local_addr->if_index;
+
+    /* And now, requeue the timer */
+    if (inst->opmode != MD_OFFLINE) {
+      delay_time = get_transmit_delay(inst, 0,
+                     UTI_DiffTimespecsToDouble(&inst->local_rx.ts, &inst->local_tx.ts));
+
+      if (kod_rate) {
+        LOG(LOGS_WARN, "Received KoD RATE from %s",
+            UTI_IPToString(&inst->remote_addr.ip_addr));
+
+        /* Back off for a while and stop ongoing burst */
+        delay_time += 4 * UTI_Log2ToDouble(inst->local_poll);
+
+        if (inst->opmode == MD_BURST_WAS_OFFLINE || inst->opmode == MD_BURST_WAS_ONLINE) {
+          inst->burst_good_samples_to_go = 0;
+        }
+      }
+
+      /* Get rid of old timeout and start a new one */
+      assert(inst->tx_timeout_id);
+      restart_timeout(inst, delay_time);
+    }
+
+    /* Update the NTP report */
+    inst->report.remote_addr = inst->remote_addr.ip_addr;
+    inst->report.local_addr = inst->local_addr.ip_addr;
+    inst->report.remote_port = inst->remote_addr.port;
+    inst->report.leap = pkt_leap;
+    inst->report.version = pkt_version;
+    inst->report.mode = NTP_LVM_TO_MODE(message->lvm);
+    inst->report.stratum = message->stratum;
+    inst->report.poll = message->poll;
+    inst->report.precision = message->precision;
+    inst->report.root_delay = pkt_root_delay;
+    inst->report.root_dispersion = pkt_root_dispersion;
+    inst->report.ref_id = pkt_refid;
+    UTI_Ntp64ToTimespec(&message->reference_ts, &inst->report.ref_time);
+    inst->report.offset = offset;
+    inst->report.peer_delay = delay;
+    inst->report.peer_dispersion = dispersion;
+    inst->report.response_time = response_time;
+    inst->report.jitter_asymmetry = SST_GetJitterAsymmetry(stats);
+    inst->report.tests = ((((((((test1 << 1 | test2) << 1 | test3) << 1 |
+                               test5) << 1 | test6) << 1 | test7) << 1 |
+                            testA) << 1 | testB) << 1 | testC) << 1 | testD;
+    inst->report.interleaved = interleaved_packet;
+    inst->report.authenticated = inst->auth_mode != AUTH_NONE;
+    inst->report.tx_tss_char = tss_chars[local_transmit.source];
+    inst->report.rx_tss_char = tss_chars[local_receive.source];
+
+    inst->report.total_valid_count++;
+  }
+
+  /* Do measurement logging */
+  if (logfileid != -1 && (log_raw_measurements || synced_packet)) {
+    LOG_FileWrite(logfileid, "%s %-15s %1c %2d %1d%1d%1d %1d%1d%1d %1d%1d%1d%d  %2d %2d %4.2f %10.3e %10.3e %10.3e %10.3e %10.3e %08"PRIX32" %1d%1c %1c %1c",
+            UTI_TimeToLogForm(sample_time.tv_sec),
+            UTI_IPToString(&inst->remote_addr.ip_addr),
+            leap_chars[pkt_leap],
+            message->stratum,
+            test1, test2, test3, test5, test6, test7, testA, testB, testC, testD,
+            inst->local_poll, message->poll,
+            inst->poll_score,
+            offset, delay, dispersion,
+            pkt_root_delay, pkt_root_dispersion, pkt_refid,
+            NTP_LVM_TO_MODE(message->lvm), interleaved_packet ? 'I' : 'B',
+            tss_chars[local_transmit.source],
+            tss_chars[local_receive.source]);
+  }            
+
+  return good_packet;
+}
+
+/* ================================================== */
+/* From RFC 5905, the standard handling of received packets, depending
+   on the mode of the packet and of the source, is :
+
+   +------------------+---------------------------------------+
+   |                  |              Packet Mode              |
+   +------------------+-------+-------+-------+-------+-------+
+   | Association Mode |   1   |   2   |   3   |   4   |   5   |
+   +------------------+-------+-------+-------+-------+-------+
+   | No Association 0 | NEWPS | DSCRD | FXMIT | MANY  | NEWBC |
+   | Symm. Active   1 | PROC  | PROC  | DSCRD | DSCRD | DSCRD |
+   | Symm. Passive  2 | PROC  | ERR   | DSCRD | DSCRD | DSCRD |
+   | Client         3 | DSCRD | DSCRD | DSCRD | PROC  | DSCRD |
+   | Server         4 | DSCRD | DSCRD | DSCRD | DSCRD | DSCRD |
+   | Broadcast      5 | DSCRD | DSCRD | DSCRD | DSCRD | DSCRD |
+   | Bcast Client   6 | DSCRD | DSCRD | DSCRD | DSCRD | PROC  |
+   +------------------+-------+-------+-------+-------+-------+
+
+   Association mode 0 is implemented in NCR_ProcessRxUnknown(), other modes
+   in NCR_ProcessRxKnown().
+
+   Broadcast, manycast and ephemeral symmetric passive associations are not
+   supported yet.
+ */
+
+/* ================================================== */
+/* This routine is called when a new packet arrives off the network,
+   and it relates to a source we have an ongoing protocol exchange with */
+
+int
+NCR_ProcessRxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
+                   NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
+{
+  int pkt_mode, proc_packet, proc_as_unknown;
+
+  if (!check_packet_format(message, length))
+    return 0;
+
+  pkt_mode = NTP_LVM_TO_MODE(message->lvm);
+  proc_packet = 0;
+  proc_as_unknown = 0;
+
+  /* Now, depending on the mode we decide what to do */
+  switch (pkt_mode) {
+    case MODE_ACTIVE:
+      switch (inst->mode) {
+        case MODE_ACTIVE:
+          /* Ordinary symmetric peering */
+          proc_packet = 1;
+          break;
+        case MODE_PASSIVE:
+          /* In this software this case should not arise, we don't
+             support unconfigured peers */
+          break;
+        case MODE_CLIENT:
+          /* This is where we have the remote configured as a server and he has
+             us configured as a peer, process as from an unknown source */
+          proc_as_unknown = 1;
+          break;
+        default:
+          /* Discard */
+          break;
+      }
+      break;
+
+    case MODE_PASSIVE:
+      switch (inst->mode) {
+        case MODE_ACTIVE:
+          /* This would arise if we have the remote configured as a peer and
+             he does not have us configured */
+          proc_packet = 1;
+          break;
+        case MODE_PASSIVE:
+          /* Error condition in RFC 5905 */
+          break;
+        default:
+          /* Discard */
+          break;
+      }
+      break;
+
+    case MODE_CLIENT:
+      /* If message is client mode, we just respond with a server mode
+         packet, regardless of what we think the remote machine is
+         supposed to be.  However, even though this is a configured
+         peer or server, we still implement access restrictions on
+         client mode operation.
+
+         This copes with the case for an isolated network where one
+         machine is set by eye and is used as the master, with the
+         other machines pointed at it.  If the master goes down, we
+         want to be able to reset its time at startup by relying on
+         one of the secondaries to flywheel it. The behaviour coded here
+         is required in the secondaries to make this possible. */
+
+      proc_as_unknown = 1;
+      break;
+
+    case MODE_SERVER:
+      switch (inst->mode) {
+        case MODE_CLIENT:
+          /* Standard case where he's a server and we're the client */
+          proc_packet = 1;
+          break;
+        default:
+          /* Discard */
+          break;
+      }
+      break;
+
+    case MODE_BROADCAST:
+      /* Just ignore these */
+      break;
+
+    default:
+      /* Obviously ignore */
+      break;
+  }
+
+  if (proc_packet) {
+    /* Check if the reply was received by the socket that sent the request */
+    if (local_addr->sock_fd != inst->local_addr.sock_fd) {
+      DEBUG_LOG("Packet received by wrong socket %d (expected %d)",
+                local_addr->sock_fd, inst->local_addr.sock_fd);
+      return 0;
+    }
+
+    /* Ignore packets from offline sources */
+    if (inst->opmode == MD_OFFLINE || inst->tx_suspended) {
+      DEBUG_LOG("Packet from offline source");
+      return 0;
+    }
+
+    return receive_packet(inst, local_addr, rx_ts, message, length);
+  } else if (proc_as_unknown) {
+    NCR_ProcessRxUnknown(&inst->remote_addr, local_addr, rx_ts, message, length);
+    /* It's not a reply to our request, don't return success */
+    return 0;
+  } else {
+    DEBUG_LOG("NTP packet discarded pkt_mode=%d our_mode=%d", pkt_mode, inst->mode);
+    return 0;
+  }
+}
+
+/* ================================================== */
+/* This routine is called when a new packet arrives off the network,
+   and it relates to a source we don't know (not our server or peer) */
+
+void
+NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
+                     NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
+{
+  NTP_Mode pkt_mode, my_mode;
+  NTP_int64 *local_ntp_rx, *local_ntp_tx;
+  NTP_Local_Timestamp local_tx, *tx_ts;
+  int pkt_version, valid_auth, log_index, interleaved, poll;
+  AuthenticationMode auth_mode;
+  uint32_t key_id;
+
+  /* Ignore the packet if it wasn't received by server socket */
+  if (!NIO_IsServerSocket(local_addr->sock_fd)) {
+    DEBUG_LOG("NTP request packet received by client socket %d", local_addr->sock_fd);
+    return;
+  }
+
+  if (!check_packet_format(message, length))
+    return;
+
+  if (!ADF_IsAllowed(access_auth_table, &remote_addr->ip_addr)) {
+    DEBUG_LOG("NTP packet received from unauthorised host %s port %d",
+              UTI_IPToString(&remote_addr->ip_addr),
+              remote_addr->port);
+    return;
+  }
+
+  pkt_mode = NTP_LVM_TO_MODE(message->lvm);
+  pkt_version = NTP_LVM_TO_VERSION(message->lvm);
+
+  switch (pkt_mode) {
+    case MODE_ACTIVE:
+      /* We are symmetric passive, even though we don't ever lock to him */
+      my_mode = MODE_PASSIVE;
+      break;
+    case MODE_CLIENT:
+      /* Reply with server packet */
+      my_mode = MODE_SERVER;
+      break;
+    case MODE_UNDEFINED:
+      /* Check if it is an NTPv1 client request (NTPv1 packets have a reserved
+         field instead of the mode field and the actual mode is determined from
+         the port numbers).  Don't ever respond with a mode 0 packet! */
+      if (pkt_version == 1 && remote_addr->port != NTP_PORT) {
+        my_mode = MODE_SERVER;
+        break;
+      }
+      /* Fall through */
+    default:
+      /* Discard */
+      DEBUG_LOG("NTP packet discarded pkt_mode=%d", pkt_mode);
+      return;
+  }
+
+  log_index = CLG_LogNTPAccess(&remote_addr->ip_addr, &rx_ts->ts);
+
+  /* Don't reply to all requests if the rate is excessive */
+  if (log_index >= 0 && CLG_LimitNTPResponseRate(log_index)) {
+      DEBUG_LOG("NTP packet discarded to limit response rate");
+      return;
+  }
+
+  /* Check if the packet includes MAC that authenticates properly */
+  valid_auth = check_packet_auth(message, length, &auth_mode, &key_id);
+
+  /* If authentication failed, select whether and how we should respond */
+  if (!valid_auth) {
+    switch (auth_mode) {
+      case AUTH_NONE:
+        /* Reply with no MAC */
+        break;
+      case AUTH_MSSNTP:
+        /* Ignore the failure (MS-SNTP servers don't check client MAC) */
+        break;
+      default:
+        /* Discard packets in other modes */
+        DEBUG_LOG("NTP packet discarded auth_mode=%d", auth_mode);
+        return;
+    }
+  }
+
+  local_ntp_rx = local_ntp_tx = NULL;
+  tx_ts = NULL;
+  interleaved = 0;
+
+  /* Check if the client is using the interleaved mode.  If it is, save the
+     new transmit timestamp and if the old transmit timestamp is valid, respond
+     in the interleaved mode.  This means the third reply to a new client is
+     the earliest one that can be interleaved.  We don't want to waste time
+     on clients that are not using the interleaved mode. */
+  if (log_index >= 0) {
+    CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
+    interleaved = !UTI_IsZeroNtp64(local_ntp_rx) &&
+                  !UTI_CompareNtp64(&message->originate_ts, local_ntp_rx) &&
+                  UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts);
+
+    if (interleaved) {
+      UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
+      tx_ts = &local_tx;
+    } else {
+      UTI_ZeroNtp64(local_ntp_tx);
+      local_ntp_tx = NULL;
+    }
+  }
+
+  /* Suggest the client to increase its polling interval if it indicates
+     the interval is shorter than the rate limiting interval */
+  poll = CLG_GetNtpMinPoll();
+  poll = MAX(poll, message->poll);
+
+  /* Send a reply */
+  transmit_packet(my_mode, interleaved, poll, pkt_version,
+                  auth_mode, key_id, &message->receive_ts, &message->transmit_ts,
+                  rx_ts, tx_ts, local_ntp_rx, NULL, remote_addr, local_addr);
+
+  /* Save the transmit timestamp */
+  if (tx_ts)
+    UTI_TimespecToNtp64(&tx_ts->ts, local_ntp_tx, NULL);
+}
+
+/* ================================================== */
+
+static void
+update_tx_timestamp(NTP_Local_Timestamp *tx_ts, NTP_Local_Timestamp *new_tx_ts,
+                    NTP_int64 *local_ntp_rx, NTP_int64 *local_ntp_tx, NTP_Packet *message)
+{
+  double delay;
+
+  if (UTI_IsZeroTimespec(&tx_ts->ts)) {
+    DEBUG_LOG("Unexpected TX update");
+    return;
+  }
+
+  /* Check if this is the last packet that was sent */
+  if ((local_ntp_rx && UTI_CompareNtp64(&message->receive_ts, local_ntp_rx)) ||
+      (local_ntp_tx && UTI_CompareNtp64(&message->transmit_ts, local_ntp_tx))) {
+    DEBUG_LOG("RX/TX timestamp mismatch");
+    return;
+  }
+
+  delay = UTI_DiffTimespecsToDouble(&new_tx_ts->ts, &tx_ts->ts);
+
+  if (delay < 0.0 || delay > MAX_TX_DELAY) {
+    DEBUG_LOG("Unacceptable TX delay %.9f", delay);
+    return;
+  }
+
+  *tx_ts = *new_tx_ts;
+
+  DEBUG_LOG("Updated TX timestamp delay=%.9f", delay);
+}
+
+/* ================================================== */
+
+void
+NCR_ProcessTxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
+                   NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length)
+{
+  NTP_Mode pkt_mode;
+
+  if (!check_packet_format(message, length))
+    return;
+
+  pkt_mode = NTP_LVM_TO_MODE(message->lvm);
+
+  /* Server and passive mode packets are responses to unknown sources */
+  if (pkt_mode != MODE_CLIENT && pkt_mode != MODE_ACTIVE) {
+    NCR_ProcessTxUnknown(&inst->remote_addr, local_addr, tx_ts, message, length);
+    return;
+  }
+
+  update_tx_timestamp(&inst->local_tx, tx_ts, &inst->local_ntp_rx, &inst->local_ntp_tx,
+                      message);
+}
+
+/* ================================================== */
+
+void
+NCR_ProcessTxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
+                     NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length)
+{
+  NTP_int64 *local_ntp_rx, *local_ntp_tx;
+  NTP_Local_Timestamp local_tx;
+  int log_index;
+
+  if (!check_packet_format(message, length))
+    return;
+
+  if (NTP_LVM_TO_MODE(message->lvm) == MODE_BROADCAST)
+    return;
+
+  log_index = CLG_GetClientIndex(&remote_addr->ip_addr);
+  if (log_index < 0)
+    return;
+
+  if (SMT_IsEnabled() && NTP_LVM_TO_MODE(message->lvm) == MODE_SERVER)
+    UTI_AddDoubleToTimespec(&tx_ts->ts, SMT_GetOffset(&tx_ts->ts), &tx_ts->ts);
+
+  CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
+
+  UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
+  update_tx_timestamp(&local_tx, tx_ts, local_ntp_rx, NULL, message);
+  UTI_TimespecToNtp64(&local_tx.ts, local_ntp_tx, NULL);
+}
+
+/* ================================================== */
+
+void
+NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double doffset)
+{
+  double delta;
+
+  if (!UTI_IsZeroTimespec(&inst->local_rx.ts))
+    UTI_AdjustTimespec(&inst->local_rx.ts, when, &inst->local_rx.ts, &delta, dfreq, doffset);
+  if (!UTI_IsZeroTimespec(&inst->local_tx.ts))
+    UTI_AdjustTimespec(&inst->local_tx.ts, when, &inst->local_tx.ts, &delta, dfreq, doffset);
+  if (!UTI_IsZeroTimespec(&inst->prev_local_tx.ts))
+    UTI_AdjustTimespec(&inst->prev_local_tx.ts, when, &inst->prev_local_tx.ts, &delta, dfreq,
+                       doffset);
+  if (!UTI_IsZeroTimespec(&inst->init_local_rx.ts))
+    UTI_AdjustTimespec(&inst->init_local_rx.ts, when, &inst->init_local_rx.ts, &delta, dfreq,
+                       doffset);
+}
+
+/* ================================================== */
+
+void
+NCR_TakeSourceOnline(NCR_Instance inst)
+{
+  switch (inst->opmode) {
+    case MD_ONLINE:
+      /* Nothing to do */
+      break;
+    case MD_OFFLINE:
+      LOG(LOGS_INFO, "Source %s online", UTI_IPToString(&inst->remote_addr.ip_addr));
+      inst->opmode = MD_ONLINE;
+      NCR_ResetInstance(inst);
+      start_initial_timeout(inst);
+      break;
+    case MD_BURST_WAS_ONLINE:
+      /* Will revert */
+      break;
+    case MD_BURST_WAS_OFFLINE:
+      inst->opmode = MD_BURST_WAS_ONLINE;
+      LOG(LOGS_INFO, "Source %s online", UTI_IPToString(&inst->remote_addr.ip_addr));
+      break;
+  }
+}
+
+/* ================================================== */
+
+void
+NCR_TakeSourceOffline(NCR_Instance inst)
+{
+  switch (inst->opmode) {
+    case MD_ONLINE:
+      LOG(LOGS_INFO, "Source %s offline", UTI_IPToString(&inst->remote_addr.ip_addr));
+      take_offline(inst);
+      break;
+    case MD_OFFLINE:
+      break;
+    case MD_BURST_WAS_ONLINE:
+      inst->opmode = MD_BURST_WAS_OFFLINE;
+      LOG(LOGS_INFO, "Source %s offline", UTI_IPToString(&inst->remote_addr.ip_addr));
+      break;
+    case MD_BURST_WAS_OFFLINE:
+      break;
+  }
+
+}
+
+/* ================================================== */
+
+void
+NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
+{
+  if (new_minpoll < MIN_MINPOLL || new_minpoll > MAX_POLL)
+    return;
+  inst->minpoll = new_minpoll;
+  LOG(LOGS_INFO, "Source %s new minpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_minpoll);
+  if (inst->maxpoll < inst->minpoll)
+    NCR_ModifyMaxpoll(inst, inst->minpoll);
+}
+
+/* ================================================== */
+
+void
+NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
+{
+  if (new_maxpoll < MIN_MAXPOLL || new_maxpoll > MAX_POLL)
+    return;
+  inst->maxpoll = new_maxpoll;
+  LOG(LOGS_INFO, "Source %s new maxpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_maxpoll);
+  if (inst->minpoll > inst->maxpoll)
+    NCR_ModifyMinpoll(inst, inst->maxpoll);
+}
+
+/* ================================================== */
+
+void
+NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay)
+{
+  inst->max_delay = CLAMP(0.0, new_max_delay, MAX_MAXDELAY);
+  LOG(LOGS_INFO, "Source %s new max delay %f",
+      UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay);
+}
+
+/* ================================================== */
+
+void
+NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio)
+{
+  inst->max_delay_ratio = CLAMP(0.0, new_max_delay_ratio, MAX_MAXDELAYRATIO);
+  LOG(LOGS_INFO, "Source %s new max delay ratio %f",
+      UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_ratio);
+}
+
+/* ================================================== */
+
+void
+NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_dev_ratio)
+{
+  inst->max_delay_dev_ratio = CLAMP(0.0, new_max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
+  LOG(LOGS_INFO, "Source %s new max delay dev ratio %f",
+      UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_dev_ratio);
+}
+
+/* ================================================== */
+
+void
+NCR_ModifyMinstratum(NCR_Instance inst, int new_min_stratum)
+{
+  inst->min_stratum = new_min_stratum;
+  LOG(LOGS_INFO, "Source %s new minstratum %d",
+      UTI_IPToString(&inst->remote_addr.ip_addr), new_min_stratum);
+}
+
+/* ================================================== */
+
+void
+NCR_ModifyPolltarget(NCR_Instance inst, int new_poll_target)
+{
+  inst->poll_target = new_poll_target;
+  LOG(LOGS_INFO, "Source %s new polltarget %d",
+      UTI_IPToString(&inst->remote_addr.ip_addr), new_poll_target);
+}
+
+/* ================================================== */
+
+void
+NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_samples)
+{
+
+  if (inst->mode == MODE_CLIENT) {
+
+    /* We want to prevent burst mode being used on symmetric active
+       associations - it will play havoc with the peer's sampling
+       strategy. (This obviously relies on us having the peer
+       configured that way if he has us configured symmetric active -
+       but there's not much else we can do.) */
+
+    switch (inst->opmode) {
+      case MD_BURST_WAS_OFFLINE:
+      case MD_BURST_WAS_ONLINE:
+        /* If already burst sampling, don't start again */
+        break;
+
+      case MD_ONLINE:
+      case MD_OFFLINE:
+        inst->opmode = inst->opmode == MD_ONLINE ?
+          MD_BURST_WAS_ONLINE : MD_BURST_WAS_OFFLINE;
+        inst->burst_good_samples_to_go = n_good_samples;
+        inst->burst_total_samples_to_go = n_total_samples;
+        start_initial_timeout(inst);
+        break;
+      default:
+        assert(0);
+        break;
+    }
+  }
+
+}
+
+/* ================================================== */
+
+void
+NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timespec *now)
+{
+  report->poll = get_transmit_poll(inst);
+
+  switch (inst->mode) {
+    case MODE_CLIENT:
+      report->mode = RPT_NTP_CLIENT;
+      break;
+    case MODE_ACTIVE:
+      report->mode = RPT_NTP_PEER;
+      break;
+    default:
+      assert(0);
+  }
+}
+
+/* ================================================== */
+
+void
+NCR_GetNTPReport(NCR_Instance inst, RPT_NTPReport *report)
+{
+  *report = inst->report;
+}
+
+/* ================================================== */
+
+int
+NCR_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_SUCCESS)
+    return 0;
+
+  /* Keep server sockets open only when an address allowed */
+  if (allow) {
+    NTP_Remote_Address remote_addr;
+
+    if (server_sock_fd4 == INVALID_SOCK_FD &&
+        ADF_IsAnyAllowed(access_auth_table, IPADDR_INET4)) {
+      remote_addr.ip_addr.family = IPADDR_INET4;
+      server_sock_fd4 = NIO_OpenServerSocket(&remote_addr);
+    }
+    if (server_sock_fd6 == INVALID_SOCK_FD &&
+        ADF_IsAnyAllowed(access_auth_table, IPADDR_INET6)) {
+      remote_addr.ip_addr.family = IPADDR_INET6;
+      server_sock_fd6 = NIO_OpenServerSocket(&remote_addr);
+    }
+  } else {
+    if (server_sock_fd4 != INVALID_SOCK_FD &&
+        !ADF_IsAnyAllowed(access_auth_table, IPADDR_INET4)) {
+      NIO_CloseServerSocket(server_sock_fd4);
+      server_sock_fd4 = INVALID_SOCK_FD;
+    }
+    if (server_sock_fd6 != INVALID_SOCK_FD &&
+        !ADF_IsAnyAllowed(access_auth_table, IPADDR_INET6)) {
+      NIO_CloseServerSocket(server_sock_fd6);
+      server_sock_fd6 = INVALID_SOCK_FD;
+    }
+  }
+
+  return 1;
+}
+
+/* ================================================== */
+
+int
+NCR_CheckAccessRestriction(IPAddr *ip_addr)
+{
+  return ADF_IsAllowed(access_auth_table, ip_addr);
+}
+
+/* ================================================== */
+
+void
+NCR_IncrementActivityCounters(NCR_Instance inst, int *online, int *offline,
+                              int *burst_online, int *burst_offline)
+{
+  switch (inst->opmode) {
+    case MD_BURST_WAS_OFFLINE:
+      ++*burst_offline;
+      break;
+    case MD_BURST_WAS_ONLINE:
+      ++*burst_online;
+      break;
+    case MD_ONLINE:
+      ++*online;
+      break;
+    case MD_OFFLINE:
+      ++*offline;
+      break;
+    default:
+      assert(0);
+      break;
+  }
+}
+
+/* ================================================== */
+
+NTP_Remote_Address *
+NCR_GetRemoteAddress(NCR_Instance inst) 
+{
+  return &inst->remote_addr;
+}
+
+/* ================================================== */
+
+uint32_t
+NCR_GetLocalRefid(NCR_Instance inst)
+{
+  return UTI_IPToRefid(&inst->local_addr.ip_addr);
+}
+
+/* ================================================== */
+
+int NCR_IsSyncPeer(NCR_Instance inst)
+{
+  return SRC_IsSyncPeer(inst->source);
+}
+
+/* ================================================== */
+
+static void
+broadcast_timeout(void *arg)
+{
+  BroadcastDestination *destination;
+  NTP_int64 orig_ts;
+  NTP_Local_Timestamp recv_ts;
+  int poll;
+
+  destination = ARR_GetElement(broadcasts, (long)arg);
+  poll = log(destination->interval) / log(2.0) + 0.5;
+
+  UTI_ZeroNtp64(&orig_ts);
+  zero_local_timestamp(&recv_ts);
+
+  transmit_packet(MODE_BROADCAST, 0, poll, NTP_VERSION, 0, 0, &orig_ts, &orig_ts, &recv_ts,
+                  NULL, NULL, NULL, &destination->addr, &destination->local_addr);
+
+  /* Requeue timeout.  We don't care if interval drifts gradually. */
+  SCH_AddTimeoutInClass(destination->interval, get_separation(poll), SAMPLING_RANDOMNESS,
+                        SCH_NtpBroadcastClass, broadcast_timeout, arg);
+}
+
+/* ================================================== */
+
+void
+NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
+{
+  BroadcastDestination *destination;
+
+  destination = (BroadcastDestination *)ARR_GetNewElement(broadcasts);
+
+  destination->addr.ip_addr = *addr;
+  destination->addr.port = port;
+  destination->local_addr.ip_addr.family = IPADDR_UNSPEC;
+  destination->local_addr.if_index = INVALID_IF_INDEX;
+  destination->local_addr.sock_fd = NIO_OpenServerSocket(&destination->addr);
+  destination->interval = CLAMP(1, interval, 1 << MAX_POLL);
+
+  SCH_AddTimeoutInClass(destination->interval, MAX_SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
+                        SCH_NtpBroadcastClass, broadcast_timeout,
+                        (void *)(long)(ARR_GetSize(broadcasts) - 1));
+}
diff --git a/chrony_3_3/ntp_core.h b/chrony_3_3/ntp_core.h
new file mode 100644
index 0000000..f788d68
--- /dev/null
+++ b/chrony_3_3/ntp_core.h
@@ -0,0 +1,142 @@
+/*
+  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 main NTP protocol engine
+  */
+
+#ifndef GOT_NTP_CORE_H
+#define GOT_NTP_CORE_H
+
+#include "sysincl.h"
+
+#include "addressing.h"
+#include "srcparams.h"
+#include "ntp.h"
+#include "reports.h"
+
+typedef enum {
+  NTP_SERVER, NTP_PEER
+} NTP_Source_Type;
+
+typedef enum {
+  NTP_TS_DAEMON = 0,
+  NTP_TS_KERNEL,
+  NTP_TS_HARDWARE
+} NTP_Timestamp_Source;
+
+typedef struct {
+  struct timespec ts;
+  double err;
+  NTP_Timestamp_Source source;
+} NTP_Local_Timestamp;
+
+/* This is a private data type used for storing the instance record for
+   each source that we are chiming with */
+typedef struct NCR_Instance_Record *NCR_Instance;
+
+/* Init and fini functions */
+extern void NCR_Initialise(void);
+extern void NCR_Finalise(void);
+
+/* Get a new instance for a server or peer */
+extern NCR_Instance NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
+
+/* Destroy an instance */
+extern void NCR_DestroyInstance(NCR_Instance instance);
+
+/* Start an instance */
+extern void NCR_StartInstance(NCR_Instance instance);
+
+/* Reset an instance */
+extern void NCR_ResetInstance(NCR_Instance inst);
+
+/* Reset polling interval of an instance */
+extern void NCR_ResetPoll(NCR_Instance instance);
+
+/* Change the remote address of an instance */
+extern void NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr);
+
+/* This routine is called when a new packet arrives off the network,
+   and it relates to a source we have an ongoing protocol exchange with */
+extern int NCR_ProcessRxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
+                              NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length);
+
+/* This routine is called when a new packet arrives off the network,
+   and we do not recognize its source */
+extern void NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
+                                 NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length);
+
+/* This routine is called when a packet is sent to a source we have
+   an ongoing protocol exchange with */
+extern void NCR_ProcessTxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
+                               NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length);
+
+/* This routine is called when a packet is sent to a destination we
+   do not recognize */
+extern void NCR_ProcessTxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
+                                 NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length);
+
+/* Slew receive and transmit times in instance records */
+extern void NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double doffset);
+
+/* Take a particular source online (i.e. start sampling it) */
+extern void NCR_TakeSourceOnline(NCR_Instance inst);
+
+/* Take a particular source offline (i.e. stop sampling it, without
+   marking it unreachable in the source selection stuff) */
+extern void NCR_TakeSourceOffline(NCR_Instance inst);
+
+extern void NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll);
+
+extern void NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll);
+
+extern void NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay);
+
+extern void NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio);
+
+extern void NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_dev_ratio);
+
+extern void NCR_ModifyMinstratum(NCR_Instance inst, int new_min_stratum);
+
+extern void NCR_ModifyPolltarget(NCR_Instance inst, int new_poll_target);
+
+extern void NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_samples);
+
+extern void NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timespec *now);
+extern void NCR_GetNTPReport(NCR_Instance inst, RPT_NTPReport *report);
+
+extern int NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all);
+extern int NCR_CheckAccessRestriction(IPAddr *ip_addr);
+
+extern void NCR_IncrementActivityCounters(NCR_Instance inst, int *online, int *offline, 
+                                          int *burst_online, int *burst_offline);
+
+extern NTP_Remote_Address *NCR_GetRemoteAddress(NCR_Instance instance);
+
+extern uint32_t NCR_GetLocalRefid(NCR_Instance inst);
+
+extern int NCR_IsSyncPeer(NCR_Instance instance);
+
+extern void NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval);
+
+#endif /* GOT_NTP_CORE_H */
diff --git a/chrony_3_3/ntp_io.c b/chrony_3_3/ntp_io.c
new file mode 100644
index 0000000..5c8c47a
--- /dev/null
+++ b/chrony_3_3/ntp_io.c
@@ -0,0 +1,853 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Timo Teras  2009
+ * Copyright (C) Miroslav Lichvar  2009, 2013-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  This file deals with the IO aspects of reading and writing NTP packets
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "array.h"
+#include "ntp_io.h"
+#include "ntp_core.h"
+#include "ntp_sources.h"
+#include "sched.h"
+#include "local.h"
+#include "logging.h"
+#include "conf.h"
+#include "privops.h"
+#include "util.h"
+
+#ifdef HAVE_LINUX_TIMESTAMPING
+#include "ntp_io_linux.h"
+#endif
+
+#define INVALID_SOCK_FD -1
+#define CMSGBUF_SIZE 256
+
+union sockaddr_in46 {
+  struct sockaddr_in in4;
+#ifdef FEAT_IPV6
+  struct sockaddr_in6 in6;
+#endif
+  struct sockaddr u;
+};
+
+struct Message {
+  union sockaddr_in46 name;
+  struct iovec iov;
+  NTP_Receive_Buffer buf;
+  /* Aligned buffer for control messages */
+  struct cmsghdr cmsgbuf[CMSGBUF_SIZE / sizeof (struct cmsghdr)];
+};
+
+#ifdef HAVE_RECVMMSG
+#define MAX_RECV_MESSAGES 4
+#define MessageHeader mmsghdr
+#else
+/* Compatible with mmsghdr */
+struct MessageHeader {
+  struct msghdr msg_hdr;
+  unsigned int msg_len;
+};
+
+#define MAX_RECV_MESSAGES 1
+#endif
+
+/* Arrays of Message and MessageHeader */
+static ARR_Instance recv_messages;
+static ARR_Instance recv_headers;
+
+/* The server/peer and client sockets for IPv4 and IPv6 */
+static int server_sock_fd4;
+static int client_sock_fd4;
+#ifdef FEAT_IPV6
+static int server_sock_fd6;
+static int client_sock_fd6;
+#endif
+
+/* Reference counters for server sockets to keep them open only when needed */
+static int server_sock_ref4;
+#ifdef FEAT_IPV6
+static int server_sock_ref6;
+#endif
+
+/* Flag indicating we create a new connected client socket for each
+   server instead of sharing client_sock_fd4 and client_sock_fd6 */
+static int separate_client_sockets;
+
+/* Flag indicating the server sockets are not created dynamically when needed,
+   either to have a socket for client requests when separate client sockets
+   are disabled and client port is equal to server port, or the server port is
+   disabled */
+static int permanent_server_sockets;
+
+/* Flag indicating that we have been initialised */
+static int initialised=0;
+
+/* ================================================== */
+
+/* Forward prototypes */
+static void read_from_socket(int sock_fd, int event, void *anything);
+
+/* ================================================== */
+
+static int
+prepare_socket(int family, int port_number, int client_only)
+{
+  union sockaddr_in46 my_addr;
+  socklen_t my_addr_len;
+  int sock_fd;
+  IPAddr bind_address;
+  int events = SCH_FILE_INPUT, on_off = 1;
+
+  /* Open Internet domain UDP socket for NTP message transmissions */
+
+  sock_fd = socket(family, SOCK_DGRAM, 0);
+
+  if (sock_fd < 0) {
+    if (!client_only) {
+      LOG(LOGS_ERR, "Could not open %s NTP socket : %s",
+          UTI_SockaddrFamilyToString(family), strerror(errno));
+    } else {
+      DEBUG_LOG("Could not open %s NTP socket : %s",
+                UTI_SockaddrFamilyToString(family), strerror(errno));
+    }
+    return INVALID_SOCK_FD;
+  }
+
+  /* Close on exec */
+  UTI_FdSetCloexec(sock_fd);
+
+  /* Prepare local address */
+  memset(&my_addr, 0, sizeof (my_addr));
+  my_addr_len = 0;
+
+  switch (family) {
+    case AF_INET:
+      if (!client_only)
+        CNF_GetBindAddress(IPADDR_INET4, &bind_address);
+      else
+        CNF_GetBindAcquisitionAddress(IPADDR_INET4, &bind_address);
+
+      if (bind_address.family == IPADDR_INET4)
+        my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4);
+      else if (port_number)
+        my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
+      else
+        break;
+
+      my_addr.in4.sin_family = family;
+      my_addr.in4.sin_port = htons(port_number);
+      my_addr_len = sizeof (my_addr.in4);
+
+      break;
+#ifdef FEAT_IPV6
+    case AF_INET6:
+      if (!client_only)
+        CNF_GetBindAddress(IPADDR_INET6, &bind_address);
+      else
+        CNF_GetBindAcquisitionAddress(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 if (port_number)
+        my_addr.in6.sin6_addr = in6addr_any;
+      else
+        break;
+
+      my_addr.in6.sin6_family = family;
+      my_addr.in6.sin6_port = htons(port_number);
+      my_addr_len = sizeof (my_addr.in6);
+
+      break;
+#endif
+    default:
+      assert(0);
+  }
+
+  /* Make the socket capable of re-using an old address if binding to a specific port */
+  if (port_number &&
+      setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on_off, sizeof(on_off)) < 0) {
+    LOG(LOGS_ERR, "Could not set %s socket option", "SO_REUSEADDR");
+    /* Don't quit - we might survive anyway */
+  }
+  
+  /* Make the socket capable of sending broadcast pkts - needed for NTP broadcast mode */
+  if (!client_only &&
+      setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *)&on_off, sizeof(on_off)) < 0) {
+    LOG(LOGS_ERR, "Could not set %s socket option", "SO_BROADCAST");
+    /* Don't quit - we might survive anyway */
+  }
+
+  /* Enable kernel/HW timestamping of packets */
+#ifdef HAVE_LINUX_TIMESTAMPING
+  if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, client_only, &events))
+#endif
+#ifdef SO_TIMESTAMPNS
+    if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, (char *)&on_off, sizeof(on_off)) < 0)
+#endif
+#ifdef SO_TIMESTAMP
+      if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMP, (char *)&on_off, sizeof(on_off)) < 0)
+        LOG(LOGS_ERR, "Could not set %s socket option", "SO_TIMESTAMP");
+#endif
+      ;
+
+#ifdef IP_FREEBIND
+  /* Allow binding to address that doesn't exist yet */
+  if (my_addr_len > 0 &&
+      setsockopt(sock_fd, IPPROTO_IP, IP_FREEBIND, (char *)&on_off, sizeof(on_off)) < 0) {
+    LOG(LOGS_ERR, "Could not set %s socket option", "IP_FREEBIND");
+  }
+#endif
+
+  if (family == AF_INET) {
+#ifdef HAVE_IN_PKTINFO
+    /* We want the local IP info on server sockets */
+    if (setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
+      LOG(LOGS_ERR, "Could not set %s socket option", "IP_PKTINFO");
+      /* Don't quit - we might survive anyway */
+    }
+#endif
+  }
+#ifdef FEAT_IPV6
+  else 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 set %s socket option", "IPV6_V6ONLY");
+    }
+#endif
+
+#ifdef HAVE_IN6_PKTINFO
+#ifdef IPV6_RECVPKTINFO
+    if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
+      LOG(LOGS_ERR, "Could not set %s socket option", "IPV6_RECVPKTINFO");
+    }
+#else
+    if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
+      LOG(LOGS_ERR, "Could not set %s socket option", "IPV6_PKTINFO");
+    }
+#endif
+#endif
+  }
+#endif
+
+  /* Bind the socket if a port or address was specified */
+  if (my_addr_len > 0 && PRV_BindSocket(sock_fd, &my_addr.u, my_addr_len) < 0) {
+    LOG(LOGS_ERR, "Could not bind %s NTP socket : %s",
+        UTI_SockaddrFamilyToString(family), strerror(errno));
+    close(sock_fd);
+    return INVALID_SOCK_FD;
+  }
+
+  /* Register handler for read and possibly exception events on the socket */
+  SCH_AddFileHandler(sock_fd, events, read_from_socket, NULL);
+
+  return sock_fd;
+}
+
+/* ================================================== */
+
+static int
+prepare_separate_client_socket(int family)
+{
+  switch (family) {
+    case IPADDR_INET4:
+      return prepare_socket(AF_INET, 0, 1);
+#ifdef FEAT_IPV6
+    case IPADDR_INET6:
+      return prepare_socket(AF_INET6, 0, 1);
+#endif
+    default:
+      return INVALID_SOCK_FD;
+  }
+}
+
+/* ================================================== */
+
+static int
+connect_socket(int sock_fd, NTP_Remote_Address *remote_addr)
+{
+  union sockaddr_in46 addr;
+  socklen_t addr_len;
+
+  addr_len = UTI_IPAndPortToSockaddr(&remote_addr->ip_addr, remote_addr->port, &addr.u);
+
+  assert(addr_len);
+
+  if (connect(sock_fd, &addr.u, addr_len) < 0) {
+    DEBUG_LOG("Could not connect NTP socket to %s:%d : %s",
+        UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
+        strerror(errno));
+    return 0;
+  }
+
+  return 1;
+}
+
+/* ================================================== */
+
+static void
+close_socket(int sock_fd)
+{
+  if (sock_fd == INVALID_SOCK_FD)
+    return;
+
+#ifdef HAVE_LINUX_TIMESTAMPING
+  NIO_Linux_NotifySocketClosing(sock_fd);
+#endif
+  SCH_RemoveFileHandler(sock_fd);
+  close(sock_fd);
+}
+
+/* ================================================== */
+
+static void
+prepare_buffers(unsigned int n)
+{
+  struct MessageHeader *hdr;
+  struct Message *msg;
+  unsigned int i;
+
+  for (i = 0; i < n; i++) {
+    msg = ARR_GetElement(recv_messages, i);
+    hdr = ARR_GetElement(recv_headers, i);
+
+    msg->iov.iov_base = &msg->buf;
+    msg->iov.iov_len = sizeof (msg->buf);
+    hdr->msg_hdr.msg_name = &msg->name;
+    hdr->msg_hdr.msg_namelen = sizeof (msg->name);
+    hdr->msg_hdr.msg_iov = &msg->iov;
+    hdr->msg_hdr.msg_iovlen = 1;
+    hdr->msg_hdr.msg_control = &msg->cmsgbuf;
+    hdr->msg_hdr.msg_controllen = sizeof (msg->cmsgbuf);
+    hdr->msg_hdr.msg_flags = 0;
+    hdr->msg_len = 0;
+  }
+}
+
+/* ================================================== */
+
+void
+NIO_Initialise(int family)
+{
+  int server_port, client_port;
+
+  assert(!initialised);
+  initialised = 1;
+
+#ifdef HAVE_LINUX_TIMESTAMPING
+  NIO_Linux_Initialise();
+#else
+  if (1) {
+    CNF_HwTsInterface *conf_iface;
+    if (CNF_GetHwTsInterface(0, &conf_iface))
+      LOG_FATAL("HW timestamping not supported");
+  }
+#endif
+
+  recv_messages = ARR_CreateInstance(sizeof (struct Message));
+  ARR_SetSize(recv_messages, MAX_RECV_MESSAGES);
+  recv_headers = ARR_CreateInstance(sizeof (struct MessageHeader));
+  ARR_SetSize(recv_headers, MAX_RECV_MESSAGES);
+  prepare_buffers(MAX_RECV_MESSAGES);
+
+  server_port = CNF_GetNTPPort();
+  client_port = CNF_GetAcquisitionPort();
+
+  /* Use separate connected sockets if client port is negative */
+  separate_client_sockets = client_port < 0;
+  if (client_port < 0)
+    client_port = 0;
+
+  permanent_server_sockets = !server_port || (!separate_client_sockets &&
+                                              client_port == server_port);
+
+  server_sock_fd4 = INVALID_SOCK_FD;
+  client_sock_fd4 = INVALID_SOCK_FD;
+  server_sock_ref4 = 0;
+#ifdef FEAT_IPV6
+  server_sock_fd6 = INVALID_SOCK_FD;
+  client_sock_fd6 = INVALID_SOCK_FD;
+  server_sock_ref6 = 0;
+#endif
+
+  if (family == IPADDR_UNSPEC || family == IPADDR_INET4) {
+    if (permanent_server_sockets && server_port)
+      server_sock_fd4 = prepare_socket(AF_INET, server_port, 0);
+    if (!separate_client_sockets) {
+      if (client_port != server_port || !server_port)
+        client_sock_fd4 = prepare_socket(AF_INET, client_port, 1);
+      else
+        client_sock_fd4 = server_sock_fd4;
+    }
+  }
+#ifdef FEAT_IPV6
+  if (family == IPADDR_UNSPEC || family == IPADDR_INET6) {
+    if (permanent_server_sockets && server_port)
+      server_sock_fd6 = prepare_socket(AF_INET6, server_port, 0);
+    if (!separate_client_sockets) {
+      if (client_port != server_port || !server_port)
+        client_sock_fd6 = prepare_socket(AF_INET6, client_port, 1);
+      else
+        client_sock_fd6 = server_sock_fd6;
+    }
+  }
+#endif
+
+  if ((server_port && server_sock_fd4 == INVALID_SOCK_FD &&
+       permanent_server_sockets 
+#ifdef FEAT_IPV6
+       && server_sock_fd6 == INVALID_SOCK_FD
+#endif
+      ) || (!separate_client_sockets && client_sock_fd4 == INVALID_SOCK_FD
+#ifdef FEAT_IPV6
+       && client_sock_fd6 == INVALID_SOCK_FD
+#endif
+      )) {
+    LOG_FATAL("Could not open NTP sockets");
+  }
+}
+
+/* ================================================== */
+
+void
+NIO_Finalise(void)
+{
+  if (server_sock_fd4 != client_sock_fd4)
+    close_socket(client_sock_fd4);
+  close_socket(server_sock_fd4);
+  server_sock_fd4 = client_sock_fd4 = INVALID_SOCK_FD;
+#ifdef FEAT_IPV6
+  if (server_sock_fd6 != client_sock_fd6)
+    close_socket(client_sock_fd6);
+  close_socket(server_sock_fd6);
+  server_sock_fd6 = client_sock_fd6 = INVALID_SOCK_FD;
+#endif
+  ARR_DestroyInstance(recv_headers);
+  ARR_DestroyInstance(recv_messages);
+
+#ifdef HAVE_LINUX_TIMESTAMPING
+  NIO_Linux_Finalise();
+#endif
+
+  initialised = 0;
+}
+
+/* ================================================== */
+
+int
+NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
+{
+  if (separate_client_sockets) {
+    int sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family);
+
+    if (sock_fd == INVALID_SOCK_FD)
+      return INVALID_SOCK_FD;
+
+    if (!connect_socket(sock_fd, remote_addr)) {
+      close_socket(sock_fd);
+      return INVALID_SOCK_FD;
+    }
+
+    return sock_fd;
+  } else {
+    switch (remote_addr->ip_addr.family) {
+      case IPADDR_INET4:
+        return client_sock_fd4;
+#ifdef FEAT_IPV6
+      case IPADDR_INET6:
+        return client_sock_fd6;
+#endif
+      default:
+        return INVALID_SOCK_FD;
+    }
+  }
+}
+
+/* ================================================== */
+
+int
+NIO_OpenServerSocket(NTP_Remote_Address *remote_addr)
+{
+  switch (remote_addr->ip_addr.family) {
+    case IPADDR_INET4:
+      if (permanent_server_sockets)
+        return server_sock_fd4;
+      if (server_sock_fd4 == INVALID_SOCK_FD)
+        server_sock_fd4 = prepare_socket(AF_INET, CNF_GetNTPPort(), 0);
+      if (server_sock_fd4 != INVALID_SOCK_FD)
+        server_sock_ref4++;
+      return server_sock_fd4;
+#ifdef FEAT_IPV6
+    case IPADDR_INET6:
+      if (permanent_server_sockets)
+        return server_sock_fd6;
+      if (server_sock_fd6 == INVALID_SOCK_FD)
+        server_sock_fd6 = prepare_socket(AF_INET6, CNF_GetNTPPort(), 0);
+      if (server_sock_fd6 != INVALID_SOCK_FD)
+        server_sock_ref6++;
+      return server_sock_fd6;
+#endif
+    default:
+      return INVALID_SOCK_FD;
+  }
+}
+
+/* ================================================== */
+
+void
+NIO_CloseClientSocket(int sock_fd)
+{
+  if (separate_client_sockets)
+    close_socket(sock_fd);
+}
+
+/* ================================================== */
+
+void
+NIO_CloseServerSocket(int sock_fd)
+{
+  if (permanent_server_sockets || sock_fd == INVALID_SOCK_FD)
+    return;
+
+  if (sock_fd == server_sock_fd4) {
+    if (--server_sock_ref4 <= 0) {
+      close_socket(server_sock_fd4);
+      server_sock_fd4 = INVALID_SOCK_FD;
+    }
+  }
+#ifdef FEAT_IPV6
+  else if (sock_fd == server_sock_fd6) {
+    if (--server_sock_ref6 <= 0) {
+      close_socket(server_sock_fd6);
+      server_sock_fd6 = INVALID_SOCK_FD;
+    }
+  }
+#endif
+  else {
+    assert(0);
+  }
+}
+
+/* ================================================== */
+
+int
+NIO_IsServerSocket(int sock_fd)
+{
+  return sock_fd != INVALID_SOCK_FD &&
+    (sock_fd == server_sock_fd4
+#ifdef FEAT_IPV6
+     || sock_fd == server_sock_fd6
+#endif
+    );
+}
+
+/* ================================================== */
+
+static void
+process_message(struct msghdr *hdr, int length, int sock_fd)
+{
+  NTP_Remote_Address remote_addr;
+  NTP_Local_Address local_addr;
+  NTP_Local_Timestamp local_ts;
+  struct timespec sched_ts;
+  struct cmsghdr *cmsg;
+
+  SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
+  local_ts.source = NTP_TS_DAEMON;
+  sched_ts = local_ts.ts;
+
+  if (hdr->msg_namelen > sizeof (union sockaddr_in46)) {
+    DEBUG_LOG("Truncated source address");
+    return;
+  }
+
+  if (hdr->msg_namelen >= sizeof (((struct sockaddr *)hdr->msg_name)->sa_family)) {
+    UTI_SockaddrToIPAndPort((struct sockaddr *)hdr->msg_name,
+                            &remote_addr.ip_addr, &remote_addr.port);
+  } else {
+    remote_addr.ip_addr.family = IPADDR_UNSPEC;
+    remote_addr.port = 0;
+  }
+
+  local_addr.ip_addr.family = IPADDR_UNSPEC;
+  local_addr.if_index = INVALID_IF_INDEX;
+  local_addr.sock_fd = sock_fd;
+
+  if (hdr->msg_flags & MSG_TRUNC) {
+    DEBUG_LOG("Received truncated message from %s:%d",
+              UTI_IPToString(&remote_addr.ip_addr), remote_addr.port);
+    return;
+  }
+
+  if (hdr->msg_flags & MSG_CTRUNC) {
+    DEBUG_LOG("Truncated control message");
+    /* Continue */
+  }
+
+  for (cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) {
+#ifdef HAVE_IN_PKTINFO
+    if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
+      struct in_pktinfo ipi;
+
+      memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
+      local_addr.ip_addr.addr.in4 = ntohl(ipi.ipi_addr.s_addr);
+      local_addr.ip_addr.family = IPADDR_INET4;
+      local_addr.if_index = ipi.ipi_ifindex;
+    }
+#endif
+
+#ifdef HAVE_IN6_PKTINFO
+    if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
+      struct in6_pktinfo ipi;
+
+      memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
+      memcpy(&local_addr.ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
+             sizeof (local_addr.ip_addr.addr.in6));
+      local_addr.ip_addr.family = IPADDR_INET6;
+      local_addr.if_index = ipi.ipi6_ifindex;
+    }
+#endif
+
+#ifdef SCM_TIMESTAMP
+    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP) {
+      struct timeval tv;
+      struct timespec ts;
+
+      memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
+      UTI_TimevalToTimespec(&tv, &ts);
+      LCL_CookTime(&ts, &local_ts.ts, &local_ts.err);
+      local_ts.source = NTP_TS_KERNEL;
+    }
+#endif
+
+#ifdef SCM_TIMESTAMPNS
+    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPNS) {
+      struct timespec ts;
+
+      memcpy(&ts, CMSG_DATA(cmsg), sizeof (ts));
+      LCL_CookTime(&ts, &local_ts.ts, &local_ts.err);
+      local_ts.source = NTP_TS_KERNEL;
+    }
+#endif
+  }
+
+#ifdef HAVE_LINUX_TIMESTAMPING
+  if (NIO_Linux_ProcessMessage(&remote_addr, &local_addr, &local_ts, hdr, length))
+    return;
+#endif
+
+  DEBUG_LOG("Received %d bytes from %s:%d to %s fd=%d if=%d tss=%d delay=%.9f",
+            length, UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
+            UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, local_addr.if_index,
+            local_ts.source, UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts));
+
+  /* Just ignore the packet if it's not of a recognized length */
+  if (length < NTP_NORMAL_PACKET_LENGTH || length > sizeof (NTP_Receive_Buffer))
+    return;
+
+  NSR_ProcessRx(&remote_addr, &local_addr, &local_ts,
+                (NTP_Packet *)hdr->msg_iov[0].iov_base, length);
+}
+
+/* ================================================== */
+
+static void
+read_from_socket(int sock_fd, int event, void *anything)
+{
+  /* This should only be called when there is something
+     to read, otherwise it may block */
+
+  struct MessageHeader *hdr;
+  unsigned int i, n;
+  int status, flags = 0;
+
+#ifdef HAVE_LINUX_TIMESTAMPING
+  if (NIO_Linux_ProcessEvent(sock_fd, event))
+    return;
+#endif
+
+  hdr = ARR_GetElements(recv_headers);
+  n = ARR_GetSize(recv_headers);
+  assert(n >= 1);
+
+  if (event == SCH_FILE_EXCEPTION) {
+#ifdef HAVE_LINUX_TIMESTAMPING
+    flags |= MSG_ERRQUEUE;
+#else
+    assert(0);
+#endif
+  }
+
+#ifdef HAVE_RECVMMSG
+  status = recvmmsg(sock_fd, hdr, n, flags | MSG_DONTWAIT, NULL);
+  if (status >= 0)
+    n = status;
+#else
+  n = 1;
+  status = recvmsg(sock_fd, &hdr[0].msg_hdr, flags);
+  if (status >= 0)
+    hdr[0].msg_len = status;
+#endif
+
+  if (status < 0) {
+#ifdef HAVE_LINUX_TIMESTAMPING
+    /* If reading from the error queue failed, the exception should be
+       for a socket error.  Clear the error to avoid a busy loop. */
+    if (flags & MSG_ERRQUEUE) {
+      int error = 0;
+      socklen_t len = sizeof (error);
+
+      if (getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, &error, &len))
+        DEBUG_LOG("Could not get SO_ERROR");
+      if (error)
+        errno = error;
+    }
+#endif
+
+    DEBUG_LOG("Could not receive from fd %d : %s", sock_fd,
+              strerror(errno));
+    return;
+  }
+
+  for (i = 0; i < n; i++) {
+    hdr = ARR_GetElement(recv_headers, i);
+    process_message(&hdr->msg_hdr, hdr->msg_len, sock_fd);
+  }
+
+  /* Restore the buffers to their original state */
+  prepare_buffers(n);
+}
+
+/* ================================================== */
+/* Send a packet to remote address from local address */
+
+int
+NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
+               NTP_Local_Address *local_addr, int length, int process_tx)
+{
+  union sockaddr_in46 remote;
+  struct msghdr msg;
+  struct iovec iov;
+  struct cmsghdr *cmsg, cmsgbuf[CMSGBUF_SIZE / sizeof (struct cmsghdr)];
+  int cmsglen;
+  socklen_t addrlen = 0;
+
+  assert(initialised);
+
+  if (local_addr->sock_fd == INVALID_SOCK_FD) {
+    DEBUG_LOG("No socket to send to %s:%d",
+              UTI_IPToString(&remote_addr->ip_addr), remote_addr->port);
+    return 0;
+  }
+
+  /* Don't set address with connected socket */
+  if (NIO_IsServerSocket(local_addr->sock_fd) || !separate_client_sockets) {
+    addrlen = UTI_IPAndPortToSockaddr(&remote_addr->ip_addr, remote_addr->port,
+                                      &remote.u);
+    if (!addrlen)
+      return 0;
+  }
+
+  if (addrlen) {
+    msg.msg_name = &remote.u;
+    msg.msg_namelen = addrlen;
+  } else {
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+  }
+
+  iov.iov_base = packet;
+  iov.iov_len = length;
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = cmsgbuf;
+  msg.msg_controllen = sizeof(cmsgbuf);
+  msg.msg_flags = 0;
+  cmsglen = 0;
+
+#ifdef HAVE_IN_PKTINFO
+  if (local_addr->ip_addr.family == IPADDR_INET4) {
+    struct in_pktinfo *ipi;
+
+    cmsg = CMSG_FIRSTHDR(&msg);
+    memset(cmsg, 0, CMSG_SPACE(sizeof(struct in_pktinfo)));
+    cmsglen += CMSG_SPACE(sizeof(struct in_pktinfo));
+
+    cmsg->cmsg_level = IPPROTO_IP;
+    cmsg->cmsg_type = IP_PKTINFO;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+
+    ipi = (struct in_pktinfo *) CMSG_DATA(cmsg);
+    ipi->ipi_spec_dst.s_addr = htonl(local_addr->ip_addr.addr.in4);
+  }
+#endif
+
+#ifdef HAVE_IN6_PKTINFO
+  if (local_addr->ip_addr.family == IPADDR_INET6) {
+    struct in6_pktinfo *ipi;
+
+    cmsg = CMSG_FIRSTHDR(&msg);
+    memset(cmsg, 0, CMSG_SPACE(sizeof(struct in6_pktinfo)));
+    cmsglen += CMSG_SPACE(sizeof(struct in6_pktinfo));
+
+    cmsg->cmsg_level = IPPROTO_IPV6;
+    cmsg->cmsg_type = IPV6_PKTINFO;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+
+    ipi = (struct in6_pktinfo *) CMSG_DATA(cmsg);
+    memcpy(&ipi->ipi6_addr.s6_addr, &local_addr->ip_addr.addr.in6,
+        sizeof(ipi->ipi6_addr.s6_addr));
+  }
+#endif
+
+#ifdef HAVE_LINUX_TIMESTAMPING
+  if (process_tx)
+   cmsglen = NIO_Linux_RequestTxTimestamp(&msg, cmsglen, local_addr->sock_fd);
+#endif
+
+  msg.msg_controllen = cmsglen;
+  /* This is apparently required on some systems */
+  if (!cmsglen)
+    msg.msg_control = NULL;
+
+  if (sendmsg(local_addr->sock_fd, &msg, 0) < 0) {
+    DEBUG_LOG("Could not send to %s:%d from %s fd %d : %s",
+        UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
+        UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd,
+        strerror(errno));
+    return 0;
+  }
+
+  DEBUG_LOG("Sent %d bytes to %s:%d from %s fd %d", length,
+      UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
+      UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd);
+
+  return 1;
+}
diff --git a/chrony_3_3/ntp_io.h b/chrony_3_3/ntp_io.h
new file mode 100644
index 0000000..1bdcf12
--- /dev/null
+++ b/chrony_3_3/ntp_io.h
@@ -0,0 +1,60 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2002
+ * 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  This is the header file for the NTP socket I/O bits.
+
+  */
+
+#ifndef GOT_NTP_IO_H
+#define GOT_NTP_IO_H
+
+#include "ntp.h"
+#include "addressing.h"
+
+/* Function to initialise the module. */
+extern void NIO_Initialise(int family);
+
+/* Function to finalise the module */
+extern void NIO_Finalise(void);
+
+/* Function to obtain a socket for sending client packets */
+extern int NIO_OpenClientSocket(NTP_Remote_Address *remote_addr);
+
+/* Function to obtain a socket for sending server/peer packets */
+extern int NIO_OpenServerSocket(NTP_Remote_Address *remote_addr);
+
+/* Function to close a socket returned by NIO_OpenClientSocket() */
+extern void NIO_CloseClientSocket(int sock_fd);
+
+/* Function to close a socket returned by NIO_OpenServerSocket() */
+extern void NIO_CloseServerSocket(int sock_fd);
+
+/* Function to check if socket is a server socket */
+extern int NIO_IsServerSocket(int sock_fd);
+
+/* Function to transmit a packet */
+extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
+                          NTP_Local_Address *local_addr, int length, int process_tx);
+
+#endif /* GOT_NTP_IO_H */
diff --git a/chrony_3_3/ntp_io_linux.c b/chrony_3_3/ntp_io_linux.c
new file mode 100644
index 0000000..22e1abb
--- /dev/null
+++ b/chrony_3_3/ntp_io_linux.c
@@ -0,0 +1,859 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Functions for NTP I/O specific to Linux
+  */
+
+/* Ugly, include our local versions from more recent kernel first */
+#include "linux-errqueue.h"
+#include "linux-net_tstamp.h"
+#define SCM_TIMESTAMPING_PKTINFO	58
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include <ifaddrs.h>
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include <net/if.h>
+
+#include "array.h"
+#include "conf.h"
+#include "hwclock.h"
+#include "local.h"
+#include "logging.h"
+#include "ntp_core.h"
+#include "ntp_io.h"
+#include "ntp_io_linux.h"
+#include "ntp_sources.h"
+#include "sched.h"
+#include "sys_linux.h"
+#include "util.h"
+
+union sockaddr_in46 {
+  struct sockaddr_in in4;
+#ifdef FEAT_IPV6
+  struct sockaddr_in6 in6;
+#endif
+  struct sockaddr u;
+};
+
+struct Interface {
+  char name[IF_NAMESIZE];
+  int if_index;
+  int phc_fd;
+  int phc_mode;
+  int phc_nocrossts;
+  /* Link speed in mbit/s */
+  int link_speed;
+  /* Start of UDP data at layer 2 for IPv4 and IPv6 */
+  int l2_udp4_ntp_start;
+  int l2_udp6_ntp_start;
+  /* Precision of PHC readings */
+  double precision;
+  /* Compensation of errors in TX and RX timestamping */
+  double tx_comp;
+  double rx_comp;
+  HCL_Instance clock;
+};
+
+/* Number of PHC readings per HW clock sample */
+#define PHC_READINGS 10
+
+/* Minimum interval between PHC readings */
+#define MIN_PHC_POLL -6
+
+/* Maximum acceptable offset between HW and daemon/kernel timestamp */
+#define MAX_TS_DELAY 1.0
+
+/* Array of Interfaces */
+static ARR_Instance interfaces;
+
+/* RX/TX and TX-specific timestamping socket options */
+static int ts_flags;
+static int ts_tx_flags;
+
+/* Flag indicating the socket options can't be changed in control messages */
+static int permanent_ts_options;
+
+/* When sending client requests to a close and fast server, it is possible that
+   a response will be received before the HW transmit timestamp of the request
+   itself.  To avoid processing of the response without the HW timestamp, we
+   monitor events returned by select() and suspend reading of packets from the
+   receive queue for up to 200 microseconds.  As the requests are normally
+   separated by at least 200 milliseconds, it is sufficient to monitor and
+   suspend one socket at a time. */
+static int monitored_socket;
+static int suspended_socket;
+static SCH_TimeoutID resume_timeout_id;
+
+#define RESUME_TIMEOUT 200.0e-6
+
+/* Unbound socket keeping the kernel RX timestamping permanently enabled
+   in order to avoid a race condition between receiving a server response
+   and the kernel actually starting to timestamp received packets after
+   enabling the timestamping and sending a request */
+static int dummy_rxts_socket;
+
+#define INVALID_SOCK_FD -3
+
+/* ================================================== */
+
+static int
+add_interface(CNF_HwTsInterface *conf_iface)
+{
+  struct ethtool_ts_info ts_info;
+  struct hwtstamp_config ts_config;
+  struct ifreq req;
+  int sock_fd, if_index, phc_fd, req_hwts_flags;
+  unsigned int i;
+  struct Interface *iface;
+
+  /* Check if the interface was not already added */
+  for (i = 0; i < ARR_GetSize(interfaces); i++) {
+    if (!strcmp(conf_iface->name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
+      return 1;
+  }
+
+  sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock_fd < 0)
+    return 0;
+
+  memset(&req, 0, sizeof (req));
+  memset(&ts_info, 0, sizeof (ts_info));
+
+  if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", conf_iface->name) >=
+      sizeof (req.ifr_name)) {
+    close(sock_fd);
+    return 0;
+  }
+
+  if (ioctl(sock_fd, SIOCGIFINDEX, &req)) {
+    DEBUG_LOG("ioctl(%s) failed : %s", "SIOCGIFINDEX", strerror(errno));
+    close(sock_fd);
+    return 0;
+  }
+
+  if_index = req.ifr_ifindex;
+
+  ts_info.cmd = ETHTOOL_GET_TS_INFO;
+  req.ifr_data = (char *)&ts_info;
+
+  if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
+    DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
+    close(sock_fd);
+    return 0;
+  }
+
+  req_hwts_flags = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_TX_HARDWARE |
+                   SOF_TIMESTAMPING_RAW_HARDWARE;
+  if ((ts_info.so_timestamping & req_hwts_flags) != req_hwts_flags) {
+    DEBUG_LOG("HW timestamping not supported on %s", req.ifr_name);
+    close(sock_fd);
+    return 0;
+  }
+
+  ts_config.flags = 0;
+  ts_config.tx_type = HWTSTAMP_TX_ON;
+
+  switch (conf_iface->rxfilter) {
+    case CNF_HWTS_RXFILTER_ANY:
+#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
+      if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL))
+        ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
+      else
+#endif
+      if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_ALL))
+        ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
+      else
+        ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
+      break;
+    case CNF_HWTS_RXFILTER_NONE:
+      ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
+      break;
+#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
+    case CNF_HWTS_RXFILTER_NTP:
+      ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
+      break;
+#endif
+    default:
+      ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
+      break;
+  }
+
+  req.ifr_data = (char *)&ts_config;
+
+  if (ioctl(sock_fd, SIOCSHWTSTAMP, &req)) {
+    DEBUG_LOG("ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno));
+    close(sock_fd);
+    return 0;
+  }
+
+  close(sock_fd);
+
+  phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
+  if (phc_fd < 0)
+    return 0;
+
+  iface = ARR_GetNewElement(interfaces);
+
+  snprintf(iface->name, sizeof (iface->name), "%s", conf_iface->name);
+  iface->if_index = if_index;
+  iface->phc_fd = phc_fd;
+  iface->phc_mode = 0;
+  iface->phc_nocrossts = conf_iface->nocrossts;
+
+  /* Start with 1 gbit and no VLANs or IPv4/IPv6 options */
+  iface->link_speed = 1000;
+  iface->l2_udp4_ntp_start = 42;
+  iface->l2_udp6_ntp_start = 62;
+
+  iface->precision = conf_iface->precision;
+  iface->tx_comp = conf_iface->tx_comp;
+  iface->rx_comp = conf_iface->rx_comp;
+
+  iface->clock = HCL_CreateInstance(UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL)));
+
+  LOG(LOGS_INFO, "Enabled HW timestamping %son %s",
+      ts_config.rx_filter == HWTSTAMP_FILTER_NONE ? "(TX only) " : "", iface->name);
+
+  return 1;
+}
+
+/* ================================================== */
+
+static int
+add_all_interfaces(CNF_HwTsInterface *conf_iface_all)
+{
+  CNF_HwTsInterface conf_iface;
+  struct ifaddrs *ifaddr, *ifa;
+  int r;
+
+  conf_iface = *conf_iface_all;
+
+  if (getifaddrs(&ifaddr)) {
+    DEBUG_LOG("getifaddrs() failed : %s", strerror(errno));
+    return 0;
+  }
+
+  for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+    conf_iface.name = ifa->ifa_name;
+    if (add_interface(&conf_iface))
+      r = 1;
+  }
+  
+  freeifaddrs(ifaddr);
+
+  /* Return success if at least one interface was added */
+  return r;
+}
+
+/* ================================================== */
+
+static void
+update_interface_speed(struct Interface *iface)
+{
+  struct ethtool_cmd cmd;
+  struct ifreq req;
+  int sock_fd, link_speed;
+
+  sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock_fd < 0)
+    return;
+
+  memset(&req, 0, sizeof (req));
+  memset(&cmd, 0, sizeof (cmd));
+
+  snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", iface->name);
+  cmd.cmd = ETHTOOL_GSET;
+  req.ifr_data = (char *)&cmd;
+
+  if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
+    DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
+    close(sock_fd);
+    return;
+  }
+
+  close(sock_fd);
+
+  link_speed = ethtool_cmd_speed(&cmd);
+
+  if (iface->link_speed != link_speed) {
+    iface->link_speed = link_speed;
+    DEBUG_LOG("Updated speed of %s to %d Mb/s", iface->name, link_speed);
+  }
+}
+
+/* ================================================== */
+
+#if defined(HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO) || defined(HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW)
+static int
+check_timestamping_option(int option)
+{
+  int sock_fd;
+
+  sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+  if (sock_fd < 0)
+    return 0;
+
+  if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &option, sizeof (option)) < 0) {
+    DEBUG_LOG("Could not enable timestamping option %x", option);
+    close(sock_fd);
+    return 0;
+  }
+
+  close(sock_fd);
+  return 1;
+}
+#endif
+
+/* ================================================== */
+
+static int
+open_dummy_socket(void)
+{
+  int sock_fd, events = 0;
+
+  if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+#ifdef FEAT_IPV6
+      && (sock_fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0
+#endif
+     )
+    return INVALID_SOCK_FD;
+
+  if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, 1, &events)) {
+    close(sock_fd);
+    return INVALID_SOCK_FD;
+  }
+
+  UTI_FdSetCloexec(sock_fd);
+  return sock_fd;
+}
+
+/* ================================================== */
+
+void
+NIO_Linux_Initialise(void)
+{
+  CNF_HwTsInterface *conf_iface;
+  unsigned int i;
+  int hwts;
+
+  interfaces = ARR_CreateInstance(sizeof (struct Interface));
+
+  /* Enable HW timestamping on specified interfaces.  If "*" was specified, try
+     all interfaces.  If no interface was specified, enable SW timestamping. */
+
+  for (i = hwts = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
+    if (!strcmp("*", conf_iface->name))
+      continue;
+    if (!add_interface(conf_iface))
+      LOG_FATAL("Could not enable HW timestamping on %s", conf_iface->name);
+    hwts = 1;
+  }
+
+  for (i = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
+    if (strcmp("*", conf_iface->name))
+      continue;
+    if (add_all_interfaces(conf_iface))
+      hwts = 1;
+    break;
+  }
+
+  ts_flags = SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE;
+  ts_tx_flags = SOF_TIMESTAMPING_TX_SOFTWARE;
+
+  if (hwts) {
+    ts_flags |= SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
+    ts_tx_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
+#ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO
+    if (check_timestamping_option(SOF_TIMESTAMPING_OPT_PKTINFO))
+      ts_flags |= SOF_TIMESTAMPING_OPT_PKTINFO;
+#endif
+#ifdef HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW
+    if (check_timestamping_option(SOF_TIMESTAMPING_OPT_TX_SWHW))
+      ts_flags |= SOF_TIMESTAMPING_OPT_TX_SWHW;
+#endif
+  }
+
+  /* Enable IP_PKTINFO in messages looped back to the error queue */
+  ts_flags |= SOF_TIMESTAMPING_OPT_CMSG;
+
+  /* Kernels before 4.7 ignore timestamping flags set in control messages */
+  permanent_ts_options = !SYS_Linux_CheckKernelVersion(4, 7);
+
+  monitored_socket = INVALID_SOCK_FD;
+  suspended_socket = INVALID_SOCK_FD;
+  dummy_rxts_socket = INVALID_SOCK_FD;
+}
+
+/* ================================================== */
+
+void
+NIO_Linux_Finalise(void)
+{
+  struct Interface *iface;
+  unsigned int i;
+
+  if (dummy_rxts_socket != INVALID_SOCK_FD)
+    close(dummy_rxts_socket);
+
+  for (i = 0; i < ARR_GetSize(interfaces); i++) {
+    iface = ARR_GetElement(interfaces, i);
+    HCL_DestroyInstance(iface->clock);
+    close(iface->phc_fd);
+  }
+
+  ARR_DestroyInstance(interfaces);
+}
+
+/* ================================================== */
+
+int
+NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
+{
+  int val, flags;
+
+  if (!ts_flags)
+    return 0;
+
+  /* Enable SCM_TIMESTAMPING control messages and the socket's error queue in
+     order to receive our transmitted packets with more accurate timestamps */
+
+  val = 1;
+  flags = ts_flags;
+
+  if (client_only || permanent_ts_options)
+    flags |= ts_tx_flags;
+
+  if (setsockopt(sock_fd, SOL_SOCKET, SO_SELECT_ERR_QUEUE, &val, sizeof (val)) < 0) {
+    LOG(LOGS_ERR, "Could not set %s socket option", "SO_SELECT_ERR_QUEUE");
+    ts_flags = 0;
+    return 0;
+  }
+
+  if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof (flags)) < 0) {
+    LOG(LOGS_ERR, "Could not set %s socket option", "SO_TIMESTAMPING");
+    ts_flags = 0;
+    return 0;
+  }
+
+  *events |= SCH_FILE_EXCEPTION;
+  return 1;
+}
+
+/* ================================================== */
+
+static void
+resume_socket(int sock_fd)
+{
+  if (monitored_socket == sock_fd)
+    monitored_socket = INVALID_SOCK_FD;
+
+  if (sock_fd == INVALID_SOCK_FD || sock_fd != suspended_socket)
+    return;
+
+  suspended_socket = INVALID_SOCK_FD;
+
+  SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_INPUT, 1);
+
+  DEBUG_LOG("Resumed RX processing %s timeout fd=%d",
+            resume_timeout_id ? "before" : "on", sock_fd);
+
+  if (resume_timeout_id) {
+    SCH_RemoveTimeout(resume_timeout_id);
+    resume_timeout_id = 0;
+  }
+}
+
+/* ================================================== */
+
+static void
+resume_timeout(void *arg)
+{
+  resume_timeout_id = 0;
+  resume_socket(suspended_socket);
+}
+
+/* ================================================== */
+
+static void
+suspend_socket(int sock_fd)
+{
+  resume_socket(suspended_socket);
+
+  suspended_socket = sock_fd;
+
+  SCH_SetFileHandlerEvent(suspended_socket, SCH_FILE_INPUT, 0);
+  resume_timeout_id = SCH_AddTimeoutByDelay(RESUME_TIMEOUT, resume_timeout, NULL);
+
+  DEBUG_LOG("Suspended RX processing fd=%d", sock_fd);
+}
+
+/* ================================================== */
+
+int
+NIO_Linux_ProcessEvent(int sock_fd, int event)
+{
+  if (sock_fd != monitored_socket)
+    return 0;
+
+  if (event == SCH_FILE_INPUT) {
+    suspend_socket(monitored_socket);
+    monitored_socket = INVALID_SOCK_FD;
+
+    /* Don't process the message yet */
+    return 1;
+  }
+
+  return 0;
+}
+
+/* ================================================== */
+
+static struct Interface *
+get_interface(int if_index)
+{
+  struct Interface *iface;
+  unsigned int i;
+
+  for (i = 0; i < ARR_GetSize(interfaces); i++) {
+    iface = ARR_GetElement(interfaces, i);
+    if (iface->if_index != if_index)
+      continue;
+
+    return iface;
+  }
+
+  return NULL;
+}
+
+/* ================================================== */
+
+static void
+process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
+                     NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family,
+                     int l2_length)
+{
+  struct timespec sample_phc_ts, sample_sys_ts, sample_local_ts, ts;
+  double rx_correction, ts_delay, phc_err, local_err;
+
+  if (HCL_NeedsNewSample(iface->clock, &local_ts->ts)) {
+    if (!SYS_Linux_GetPHCSample(iface->phc_fd, iface->phc_nocrossts, iface->precision,
+                                &iface->phc_mode, &sample_phc_ts, &sample_sys_ts,
+                                &phc_err))
+      return;
+
+    LCL_CookTime(&sample_sys_ts, &sample_local_ts, &local_err);
+    HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts,
+                         phc_err + local_err);
+
+    update_interface_speed(iface);
+  }
+
+  /* We need to transpose RX timestamps as hardware timestamps are normally
+     preamble timestamps and RX timestamps in NTP are supposed to be trailer
+     timestamps.  If we don't know the length of the packet at layer 2, we
+     make an assumption that UDP data start at the same position as in the
+     last transmitted packet which had a HW TX timestamp. */
+  if (rx_ntp_length && iface->link_speed) {
+    if (!l2_length)
+      l2_length = (family == IPADDR_INET4 ? iface->l2_udp4_ntp_start :
+                   iface->l2_udp6_ntp_start) + rx_ntp_length + 4;
+    rx_correction = l2_length / (1.0e6 / 8 * iface->link_speed);
+
+    UTI_AddDoubleToTimespec(hw_ts, rx_correction, hw_ts);
+  }
+
+  if (!HCL_CookTime(iface->clock, hw_ts, &ts, &local_err))
+    return;
+
+  if (!rx_ntp_length && iface->tx_comp)
+    UTI_AddDoubleToTimespec(&ts, iface->tx_comp, &ts);
+  else if (rx_ntp_length && iface->rx_comp)
+    UTI_AddDoubleToTimespec(&ts, -iface->rx_comp, &ts);
+
+  ts_delay = UTI_DiffTimespecsToDouble(&local_ts->ts, &ts);
+
+  if (fabs(ts_delay) > MAX_TS_DELAY) {
+    DEBUG_LOG("Unacceptable timestamp delay %.9f", ts_delay);
+    return;
+  }
+
+  local_ts->ts = ts;
+  local_ts->err = local_err;
+  local_ts->source = NTP_TS_HARDWARE;
+}
+
+/* ================================================== */
+/* Extract UDP data from a layer 2 message.  Supported is Ethernet
+   with optional VLAN tags. */
+
+static int
+extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
+{
+  unsigned char *msg_start = msg;
+  union sockaddr_in46 addr;
+
+  remote_addr->ip_addr.family = IPADDR_UNSPEC;
+  remote_addr->port = 0;
+
+  /* Skip MACs */
+  if (len < 12)
+    return 0;
+  len -= 12, msg += 12;
+
+  /* Skip VLAN tag(s) if present */
+  while (len >= 4 && msg[0] == 0x81 && msg[1] == 0x00)
+    len -= 4, msg += 4;
+
+  /* Skip IPv4 or IPv6 ethertype */
+  if (len < 2 || !((msg[0] == 0x08 && msg[1] == 0x00) ||
+                   (msg[0] == 0x86 && msg[1] == 0xdd)))
+    return 0;
+  len -= 2, msg += 2;
+
+  /* Parse destination address and port from IPv4/IPv6 and UDP headers */
+  if (len >= 20 && msg[0] >> 4 == 4) {
+    int ihl = (msg[0] & 0xf) * 4;
+
+    if (len < ihl + 8 || msg[9] != 17)
+      return 0;
+
+    memcpy(&addr.in4.sin_addr.s_addr, msg + 16, sizeof (uint32_t));
+    addr.in4.sin_port = *(uint16_t *)(msg + ihl + 2);
+    addr.in4.sin_family = AF_INET;
+    len -= ihl + 8, msg += ihl + 8;
+#ifdef FEAT_IPV6
+  } else if (len >= 48 && msg[0] >> 4 == 6) {
+    int eh_len, next_header = msg[6];
+
+    memcpy(&addr.in6.sin6_addr.s6_addr, msg + 24, 16);
+    len -= 40, msg += 40;
+
+    /* Skip IPv6 extension headers if present */
+    while (next_header != 17) {
+      switch (next_header) {
+        case 44:  /* Fragment Header */
+          /* Process only the first fragment */
+          if (ntohs(*(uint16_t *)(msg + 2)) >> 3 != 0)
+            return 0;
+          eh_len = 8;
+          break;
+        case 0:   /* Hop-by-Hop Options */
+        case 43:  /* Routing Header */
+        case 60:  /* Destination Options */
+        case 135: /* Mobility Header */
+          eh_len = 8 * (msg[1] + 1);
+          break;
+        case 51:  /* Authentication Header */
+          eh_len = 4 * (msg[1] + 2);
+          break;
+        default:
+          return 0;
+      }
+
+      if (eh_len < 8 || len < eh_len + 8)
+        return 0;
+
+      next_header = msg[0];
+      len -= eh_len, msg += eh_len;
+    }
+
+    addr.in6.sin6_port = *(uint16_t *)(msg + 2);
+    addr.in6.sin6_family = AF_INET6;
+    len -= 8, msg += 8;
+#endif
+  } else {
+    return 0;
+  }
+
+  UTI_SockaddrToIPAndPort(&addr.u, &remote_addr->ip_addr, &remote_addr->port);
+
+  /* Move the message to fix alignment of its fields */
+  if (len > 0)
+    memmove(msg_start, msg, len);
+
+  return len;
+}
+
+/* ================================================== */
+
+int
+NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
+                         NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length)
+{
+  struct Interface *iface;
+  struct cmsghdr *cmsg;
+  int is_tx, ts_if_index, l2_length;
+
+  is_tx = hdr->msg_flags & MSG_ERRQUEUE;
+  iface = NULL;
+  ts_if_index = local_addr->if_index;
+  l2_length = 0;
+
+  for (cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) {
+#ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO
+    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING_PKTINFO) {
+      struct scm_ts_pktinfo ts_pktinfo;
+
+      memcpy(&ts_pktinfo, CMSG_DATA(cmsg), sizeof (ts_pktinfo));
+
+      ts_if_index = ts_pktinfo.if_index;
+      l2_length = ts_pktinfo.pkt_length;
+
+      DEBUG_LOG("Received HW timestamp info if=%d length=%d", ts_if_index, l2_length);
+    }
+#endif
+
+    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING) {
+      struct scm_timestamping ts3;
+
+      memcpy(&ts3, CMSG_DATA(cmsg), sizeof (ts3));
+
+      if (!UTI_IsZeroTimespec(&ts3.ts[2])) {
+        iface = get_interface(ts_if_index);
+        if (iface) {
+          process_hw_timestamp(iface, &ts3.ts[2], local_ts, !is_tx ? length : 0,
+                               remote_addr->ip_addr.family, l2_length);
+        } else {
+          DEBUG_LOG("HW clock not found for interface %d", ts_if_index);
+        }
+
+        /* If a HW transmit timestamp was received, resume processing
+           of non-error messages on this socket */
+        if (is_tx)
+          resume_socket(local_addr->sock_fd);
+      }
+
+      if (local_ts->source == NTP_TS_DAEMON && !UTI_IsZeroTimespec(&ts3.ts[0]) &&
+          (!is_tx || UTI_IsZeroTimespec(&ts3.ts[2]))) {
+        LCL_CookTime(&ts3.ts[0], &local_ts->ts, &local_ts->err);
+        local_ts->source = NTP_TS_KERNEL;
+      }
+    }
+
+    if ((cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) ||
+        (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_RECVERR)) {
+      struct sock_extended_err err;
+
+      memcpy(&err, CMSG_DATA(cmsg), sizeof (err));
+
+      if (err.ee_errno != ENOMSG || err.ee_info != SCM_TSTAMP_SND ||
+          err.ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
+        DEBUG_LOG("Unknown extended error");
+        /* Drop the message */
+        return 1;
+      }
+    }
+  }
+
+  /* If the kernel is slow with enabling RX timestamping, open a dummy
+     socket to keep the kernel RX timestamping permanently enabled */
+  if (!is_tx && local_ts->source == NTP_TS_DAEMON && ts_flags) {
+    DEBUG_LOG("Missing kernel RX timestamp");
+    if (dummy_rxts_socket == INVALID_SOCK_FD)
+      dummy_rxts_socket = open_dummy_socket();
+  }
+
+  /* Return the message if it's not received from the error queue */
+  if (!is_tx)
+    return 0;
+
+  /* The data from the error queue includes all layers up to UDP.  We have to
+     extract the UDP data and also the destination address with port as there
+     currently doesn't seem to be a better way to get them both. */
+  l2_length = length;
+  length = extract_udp_data(hdr->msg_iov[0].iov_base, remote_addr, length);
+
+  DEBUG_LOG("Received %d (%d) bytes from error queue for %s:%d fd=%d if=%d tss=%d",
+            l2_length, length, UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
+            local_addr->sock_fd, local_addr->if_index, local_ts->source);
+
+  /* Update assumed position of UDP data at layer 2 for next received packet */
+  if (iface && length) {
+    if (remote_addr->ip_addr.family == IPADDR_INET4)
+      iface->l2_udp4_ntp_start = l2_length - length;
+    else if (remote_addr->ip_addr.family == IPADDR_INET6)
+      iface->l2_udp6_ntp_start = l2_length - length;
+  }
+
+  /* Drop the message if it has no timestamp or its processing failed */
+  if (local_ts->source == NTP_TS_DAEMON) {
+    DEBUG_LOG("Missing TX timestamp");
+    return 1;
+  }
+
+  if (length < NTP_NORMAL_PACKET_LENGTH)
+    return 1;
+
+  NSR_ProcessTx(remote_addr, local_addr, local_ts,
+                (NTP_Packet *)hdr->msg_iov[0].iov_base, length);
+
+  return 1;
+}
+
+/* ================================================== */
+
+int
+NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd)
+{
+  struct cmsghdr *cmsg;
+
+  if (!ts_flags)
+    return cmsglen;
+
+  /* If a HW transmit timestamp is requested on a client socket, monitor
+     events on the socket in order to avoid processing of a fast response
+     without the HW timestamp of the request */
+  if (ts_tx_flags & SOF_TIMESTAMPING_TX_HARDWARE && !NIO_IsServerSocket(sock_fd))
+    monitored_socket = sock_fd;
+
+  /* Check if TX timestamping is disabled on this socket */
+  if (permanent_ts_options || !NIO_IsServerSocket(sock_fd))
+    return cmsglen;
+
+  /* Add control message that will enable TX timestamping for this message.
+     Don't use CMSG_NXTHDR as the one in glibc is buggy for creating new
+     control messages. */
+  cmsg = (struct cmsghdr *)((char *)CMSG_FIRSTHDR(msg) + cmsglen);
+  memset(cmsg, 0, CMSG_SPACE(sizeof (ts_tx_flags)));
+  cmsglen += CMSG_SPACE(sizeof (ts_tx_flags));
+
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SO_TIMESTAMPING;
+  cmsg->cmsg_len = CMSG_LEN(sizeof (ts_tx_flags));
+
+  memcpy(CMSG_DATA(cmsg), &ts_tx_flags, sizeof (ts_tx_flags));
+
+  return cmsglen;
+}
+
+/* ================================================== */
+
+void
+NIO_Linux_NotifySocketClosing(int sock_fd)
+{
+  resume_socket(sock_fd);
+}
diff --git a/chrony_3_3/ntp_io_linux.h b/chrony_3_3/ntp_io_linux.h
new file mode 100644
index 0000000..ed37e6a
--- /dev/null
+++ b/chrony_3_3/ntp_io_linux.h
@@ -0,0 +1,45 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  This is the header file for the Linux-specific NTP socket I/O bits.
+  */
+
+#ifndef GOT_NTP_IO_LINUX_H
+#define GOT_NTP_IO_LINUX_H
+
+extern void NIO_Linux_Initialise(void);
+
+extern void NIO_Linux_Finalise(void);
+
+extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
+
+extern int NIO_Linux_ProcessEvent(int sock_fd, int event);
+
+extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
+                                    NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length);
+
+extern int NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd);
+
+extern void NIO_Linux_NotifySocketClosing(int sock_fd);
+
+#endif
diff --git a/chrony_3_3/ntp_signd.c b/chrony_3_3/ntp_signd.c
new file mode 100644
index 0000000..6328b61
--- /dev/null
+++ b/chrony_3_3/ntp_signd.c
@@ -0,0 +1,379 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Support for MS-SNTP authentication in Samba (ntp_signd)
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "array.h"
+#include "conf.h"
+#include "logging.h"
+#include "ntp_io.h"
+#include "ntp_signd.h"
+#include "sched.h"
+#include "util.h"
+
+/* Declarations per samba/source4/librpc/idl/ntp_signd.idl */
+
+#define SIGND_VERSION 0
+
+typedef enum {
+  SIGN_TO_CLIENT = 0,
+  ASK_SERVER_TO_SIGN = 1,
+  CHECK_SERVER_SIGNATURE = 2,
+  SIGNING_SUCCESS = 3,
+  SIGNING_FAILURE = 4,
+} SigndOp;
+
+typedef struct {
+  uint32_t length;
+  uint32_t version;
+  uint32_t op;
+  uint16_t packet_id;
+  uint16_t _pad;
+  uint32_t key_id;
+  NTP_Packet packet_to_sign;
+} SigndRequest;
+
+typedef struct {
+  uint32_t length;
+  uint32_t version;
+  uint32_t op;
+  uint32_t packet_id;
+  NTP_Packet signed_packet;
+} SigndResponse;
+
+typedef struct {
+  NTP_Remote_Address remote_addr;
+  NTP_Local_Address local_addr;
+
+  int sent;
+  int received;
+  int request_length;
+  struct timespec request_ts;
+  SigndRequest request;
+  SigndResponse response;
+} SignInstance;
+
+/* As the communication with ntp_signd is asynchronous, incoming packets are
+   saved in a queue in order to avoid loss when they come in bursts */
+
+#define MAX_QUEUE_LENGTH 16U
+#define NEXT_QUEUE_INDEX(index) (((index) + 1) % MAX_QUEUE_LENGTH)
+#define IS_QUEUE_EMPTY() (queue_head == queue_tail)
+
+/* Fixed-size array of SignInstance */
+static ARR_Instance queue;
+static unsigned int queue_head;
+static unsigned int queue_tail;
+
+#define INVALID_SOCK_FD -1
+
+/* Unix domain socket connected to ntp_signd */
+static int sock_fd;
+
+#define MIN_AUTH_DELAY 1.0e-5
+#define MAX_AUTH_DELAY 1.0e-2
+
+/* Average time needed for signing one packet.  This is used to adjust the
+   transmit timestamp in NTP packets.  The timestamp won't be very accurate as
+   the delay is variable, but it should be good enough for MS-SNTP clients. */
+static double auth_delay;
+
+/* Flag indicating if the MS-SNTP authentication is enabled */
+static int enabled;
+
+/* ================================================== */
+
+static void read_write_socket(int sock_fd, int event, void *anything);
+
+/* ================================================== */
+
+static void
+close_socket(void)
+{
+  SCH_RemoveFileHandler(sock_fd);
+  close(sock_fd);
+  sock_fd = INVALID_SOCK_FD;
+
+  /* Empty the queue */
+  queue_head = queue_tail = 0;
+}
+
+/* ================================================== */
+
+static int
+open_socket(void)
+{
+  struct sockaddr_un s;
+
+  if (sock_fd >= 0)
+    return 1;
+
+  sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (sock_fd < 0) {
+    DEBUG_LOG("Could not open signd socket : %s", strerror(errno));
+    return 0;
+  }
+
+  UTI_FdSetCloexec(sock_fd);
+  SCH_AddFileHandler(sock_fd, SCH_FILE_INPUT, read_write_socket, NULL);
+
+  s.sun_family = AF_UNIX;
+  if (snprintf(s.sun_path, sizeof (s.sun_path), "%s/socket",
+               CNF_GetNtpSigndSocket()) >= sizeof (s.sun_path)) {
+    DEBUG_LOG("signd socket path too long");
+    close_socket();
+    return 0;
+  }
+
+  if (connect(sock_fd, (struct sockaddr *)&s, sizeof (s)) < 0) {
+    DEBUG_LOG("Could not connect to signd : %s", strerror(errno));
+    close_socket();
+    return 0;
+  }
+
+  DEBUG_LOG("Connected to signd");
+
+  return 1;
+}
+
+/* ================================================== */
+
+static void
+process_response(SignInstance *inst)
+{
+  struct timespec ts;
+  double delay;
+
+  if (ntohs(inst->request.packet_id) != ntohl(inst->response.packet_id)) {
+    DEBUG_LOG("Invalid response ID");
+    return;
+  }
+
+  if (ntohl(inst->response.op) != SIGNING_SUCCESS) {
+    DEBUG_LOG("Signing failed");
+    return;
+  }
+
+  /* Check if the file descriptor is still valid */
+  if (!NIO_IsServerSocket(inst->local_addr.sock_fd)) {
+    DEBUG_LOG("Invalid NTP socket");
+    return;
+  }
+
+  SCH_GetLastEventTime(NULL, NULL, &ts);
+  delay = UTI_DiffTimespecsToDouble(&ts, &inst->request_ts);
+
+  DEBUG_LOG("Signing succeeded (delay %f)", delay);
+
+  /* Send the signed NTP packet */
+  NIO_SendPacket(&inst->response.signed_packet, &inst->remote_addr, &inst->local_addr,
+                 ntohl(inst->response.length) + sizeof (inst->response.length) -
+                 offsetof(SigndResponse, signed_packet), 0);
+
+  /* Update exponential moving average of the authentication delay */
+  delay = CLAMP(MIN_AUTH_DELAY, delay, MAX_AUTH_DELAY);
+  auth_delay += 0.1 * (delay - auth_delay);
+}
+
+/* ================================================== */
+
+static void
+read_write_socket(int sock_fd, int event, void *anything)
+{
+  SignInstance *inst;
+  uint32_t response_length;
+  int s;
+
+  inst = ARR_GetElement(queue, queue_head);
+
+  if (event == SCH_FILE_OUTPUT) {
+    assert(!IS_QUEUE_EMPTY());
+    assert(inst->sent < inst->request_length);
+
+    if (!inst->sent)
+      SCH_GetLastEventTime(NULL, NULL, &inst->request_ts);
+
+    s = send(sock_fd, (char *)&inst->request + inst->sent,
+             inst->request_length - inst->sent, 0);
+
+    if (s < 0) {
+      DEBUG_LOG("signd socket error: %s", strerror(errno));
+      close_socket();
+      return;
+    }
+
+    DEBUG_LOG("Sent %d bytes to signd", s);
+    inst->sent += s;
+
+    /* Try again later if the request is not complete yet */
+    if (inst->sent < inst->request_length)
+      return;
+
+    /* Disable output and wait for a response */
+    SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 0);
+  }
+
+  if (event == SCH_FILE_INPUT) {
+    if (IS_QUEUE_EMPTY()) {
+        DEBUG_LOG("Unexpected signd response");
+        close_socket();
+        return;
+    }
+
+    assert(inst->received < sizeof (inst->response));
+    s = recv(sock_fd, (char *)&inst->response + inst->received,
+             sizeof (inst->response) - inst->received, 0);
+
+    if (s <= 0) {
+      if (s < 0)
+        DEBUG_LOG("signd socket error: %s", strerror(errno));
+      else
+        DEBUG_LOG("signd socket closed");
+
+      close_socket();
+      return;
+    }
+
+    DEBUG_LOG("Received %d bytes from signd", s);
+    inst->received += s;
+
+    if (inst->received < sizeof (inst->response.length))
+      return;
+
+    response_length = ntohl(inst->response.length) + sizeof (inst->response.length);
+
+    if (response_length < offsetof(SigndResponse, signed_packet) ||
+        response_length > sizeof (SigndResponse)) {
+      DEBUG_LOG("Invalid response length");
+      close_socket();
+      return;
+    }
+
+    /* Wait for more data if not complete yet */
+    if (inst->received < response_length)
+      return;
+
+    process_response(inst);
+
+    /* Move the head and enable output for the next packet */
+    queue_head = NEXT_QUEUE_INDEX(queue_head);
+    if (!IS_QUEUE_EMPTY())
+      SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
+  }
+}
+
+/* ================================================== */
+
+void
+NSD_Initialise()
+{
+  sock_fd = INVALID_SOCK_FD;
+  auth_delay = MIN_AUTH_DELAY;
+  enabled = CNF_GetNtpSigndSocket() && CNF_GetNtpSigndSocket()[0];
+
+  if (!enabled)
+    return;
+
+  queue = ARR_CreateInstance(sizeof (SignInstance));
+  ARR_SetSize(queue, MAX_QUEUE_LENGTH);
+  queue_head = queue_tail = 0;
+
+  LOG(LOGS_INFO, "MS-SNTP authentication enabled");
+}
+
+/* ================================================== */
+
+void
+NSD_Finalise()
+{
+  if (!enabled)
+    return;
+  if (sock_fd != INVALID_SOCK_FD)
+    close_socket();
+  ARR_DestroyInstance(queue);
+}
+
+/* ================================================== */
+
+extern int NSD_GetAuthDelay(uint32_t key_id)
+{
+  return 1.0e9 * auth_delay;
+}
+
+/* ================================================== */
+
+int
+NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length)
+{
+  SignInstance *inst;
+
+  if (!enabled) {
+    DEBUG_LOG("signd disabled");
+    return 0;
+  }
+
+  if (queue_head == NEXT_QUEUE_INDEX(queue_tail)) {
+    DEBUG_LOG("signd queue full");
+    return 0;
+  }
+
+  if (length != NTP_NORMAL_PACKET_LENGTH) {
+    DEBUG_LOG("Invalid packet length");
+    return 0;
+  }
+
+  if (!open_socket())
+    return 0;
+
+  inst = ARR_GetElement(queue, queue_tail);
+  inst->remote_addr = *remote_addr;
+  inst->local_addr = *local_addr;
+  inst->sent = 0;
+  inst->received = 0;
+  inst->request_length = offsetof(SigndRequest, packet_to_sign) + length;
+
+  /* The length field doesn't include itself */
+  inst->request.length = htonl(inst->request_length - sizeof (inst->request.length));
+  inst->request.version = htonl(SIGND_VERSION);
+  inst->request.op = htonl(SIGN_TO_CLIENT);
+  inst->request.packet_id = htons(queue_tail);
+  inst->request._pad = 0;
+  inst->request.key_id = htonl(key_id);
+
+  memcpy(&inst->request.packet_to_sign, packet, length);
+
+  /* Enable output if there was no pending request */
+  if (IS_QUEUE_EMPTY())
+    SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
+
+  queue_tail = NEXT_QUEUE_INDEX(queue_tail);
+
+  DEBUG_LOG("Packet added to signd queue (%u:%u)", queue_head, queue_tail);
+
+  return 1;
+}
diff --git a/chrony_3_3/ntp_signd.h b/chrony_3_3/ntp_signd.h
new file mode 100644
index 0000000..f45a5cb
--- /dev/null
+++ b/chrony_3_3/ntp_signd.h
@@ -0,0 +1,44 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Header for MS-SNTP authentication via Samba (ntp_signd) */
+
+#ifndef GOT_NTP_SIGND_H
+#define GOT_NTP_SIGND_H
+
+#include "addressing.h"
+#include "ntp.h"
+
+/* Initialisation function */
+extern void NSD_Initialise(void);
+
+/* Finalisation function */
+extern void NSD_Finalise(void);
+
+/* Function to get an estimate of delay due to signing */
+extern int NSD_GetAuthDelay(uint32_t key_id);
+
+/* Function to sign an NTP packet and send it */
+extern int NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);
+
+#endif
diff --git a/chrony_3_3/ntp_sources.c b/chrony_3_3/ntp_sources.c
new file mode 100644
index 0000000..e7fb60f
--- /dev/null
+++ b/chrony_3_3/ntp_sources.c
@@ -0,0 +1,1172 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2011-2012, 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Functions which manage the pool of NTP sources that we are currently
+  a client of or peering with.
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "array.h"
+#include "ntp_sources.h"
+#include "ntp_core.h"
+#include "util.h"
+#include "logging.h"
+#include "local.h"
+#include "memory.h"
+#include "nameserv_async.h"
+#include "privops.h"
+#include "sched.h"
+
+/* ================================================== */
+
+/* Record type private to this file, used to store information about
+   particular sources */
+typedef struct {
+  NTP_Remote_Address *remote_addr; /* The address of this source, non-NULL
+                                      means this slot in table is in use */
+  NCR_Instance data;            /* Data for the protocol engine for this source */
+  char *name;                   /* Name of the source, may be NULL */
+  int pool;                     /* Number of the pool from which was this source
+                                   added or INVALID_POOL */
+  int tentative;                /* Flag indicating there was no valid response
+                                   received from the source yet */
+} SourceRecord;
+
+/* Hash table of SourceRecord, its size is a power of two and it's never
+   more than half full */
+static ARR_Instance records;
+
+/* Number of sources in the hash table */
+static int n_sources;
+
+/* Flag indicating new sources will be started automatically when added */
+static int auto_start_sources = 0;
+
+/* Source with unknown address (which may be resolved later) */
+struct UnresolvedSource {
+  char *name;
+  int port;
+  int random_order;
+  int replacement;
+  union {
+    struct {
+      NTP_Source_Type type;
+      SourceParameters params;
+      int pool;
+      int max_new_sources;
+    } new_source;
+    NTP_Remote_Address replace_source;
+  };
+  struct UnresolvedSource *next;
+};
+
+#define RESOLVE_INTERVAL_UNIT 7
+#define MIN_RESOLVE_INTERVAL 2
+#define MAX_RESOLVE_INTERVAL 9
+#define MIN_REPLACEMENT_INTERVAL 8
+
+static struct UnresolvedSource *unresolved_sources = NULL;
+static int resolving_interval = 0;
+static SCH_TimeoutID resolving_id;
+static struct UnresolvedSource *resolving_source = NULL;
+static NSR_SourceResolvingEndHandler resolving_end_handler = NULL;
+
+#define MAX_POOL_SOURCES 16
+#define INVALID_POOL (-1)
+
+/* Pool of sources with the same name */
+struct SourcePool {
+  /* Number of sources added from this pool (ignoring tentative sources) */
+  int sources;
+  /* Maximum number of sources */
+  int max_sources;
+};
+
+/* Array of SourcePool */
+static ARR_Instance pools;
+
+/* ================================================== */
+/* Forward prototypes */
+
+static void resolve_sources(void *arg);
+static void rehash_records(void);
+static void clean_source_record(SourceRecord *record);
+
+static void
+slew_sources(struct timespec *raw,
+             struct timespec *cooked,
+             double dfreq,
+             double doffset,
+             LCL_ChangeType change_type,
+             void *anything);
+
+/* ================================================== */
+
+/* Flag indicating whether module is initialised */
+static int initialised = 0;
+
+/* ================================================== */
+
+static SourceRecord *
+get_record(unsigned index)
+{
+  return (SourceRecord *)ARR_GetElement(records, index);
+}
+
+/* ================================================== */
+
+void
+NSR_Initialise(void)
+{
+  n_sources = 0;
+  initialised = 1;
+
+  records = ARR_CreateInstance(sizeof (SourceRecord));
+  rehash_records();
+
+  pools = ARR_CreateInstance(sizeof (struct SourcePool));
+
+  LCL_AddParameterChangeHandler(slew_sources, NULL);
+}
+
+/* ================================================== */
+
+void
+NSR_Finalise(void)
+{
+  SourceRecord *record;
+  struct UnresolvedSource *us;
+  unsigned int i;
+
+  ARR_DestroyInstance(pools);
+
+  for (i = 0; i < ARR_GetSize(records); i++) {
+    record = get_record(i);
+    if (record->remote_addr)
+      clean_source_record(record);
+  }
+
+  ARR_DestroyInstance(records);
+
+  while (unresolved_sources) {
+    us = unresolved_sources;
+    unresolved_sources = us->next;
+    Free(us->name);
+    Free(us);
+  }
+
+  initialised = 0;
+}
+
+/* ================================================== */
+/* Return slot number and whether the IP address was matched or not.
+   found = 0 => Neither IP nor port matched, empty slot returned
+   found = 1 => Only IP matched, port doesn't match
+   found = 2 => Both IP and port matched.
+
+   It is assumed that there can only ever be one record for a
+   particular IP address.  (If a different port comes up, it probably
+   means someone is running ntpdate -d or something).  Thus, if we
+   match the IP address we stop the search regardless of whether the
+   port number matches.
+
+  */
+
+static void
+find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
+{
+  SourceRecord *record;
+  uint32_t hash;
+  unsigned int i, size;
+  unsigned short port;
+
+  size = ARR_GetSize(records);
+
+  *slot = 0;
+  *found = 0;
+  
+  if (remote_addr->ip_addr.family != IPADDR_INET4 &&
+      remote_addr->ip_addr.family != IPADDR_INET6)
+    return;
+
+  hash = UTI_IPToHash(&remote_addr->ip_addr);
+  port = remote_addr->port;
+
+  for (i = 0; i < size / 2; i++) {
+    /* Use quadratic probing */
+    *slot = (hash + (i + i * i) / 2) % size;
+    record = get_record(*slot);
+
+    if (!record->remote_addr)
+      break;
+
+    if (!UTI_CompareIPs(&record->remote_addr->ip_addr,
+                        &remote_addr->ip_addr, NULL)) {
+      *found = record->remote_addr->port == port ? 2 : 1;
+      return;
+    }
+  }
+}
+
+/* ================================================== */
+/* Check if hash table of given size is sufficient to contain sources */
+
+static int
+check_hashtable_size(unsigned int sources, unsigned int size)
+{
+  return sources * 2 <= size;
+}
+
+/* ================================================== */
+
+static void
+rehash_records(void)
+{
+  SourceRecord *temp_records;
+  unsigned int i, old_size, new_size;
+  int slot, found;
+
+  old_size = ARR_GetSize(records);
+
+  temp_records = MallocArray(SourceRecord, old_size);
+  memcpy(temp_records, ARR_GetElements(records), old_size * sizeof (SourceRecord));
+
+  /* The size of the hash table is always a power of two */
+  for (new_size = 1; !check_hashtable_size(n_sources, new_size); new_size *= 2)
+    ;
+
+  ARR_SetSize(records, new_size);
+
+  for (i = 0; i < new_size; i++)
+    get_record(i)->remote_addr = NULL;
+
+  for (i = 0; i < old_size; i++) {
+    if (!temp_records[i].remote_addr)
+      continue;
+
+    find_slot(temp_records[i].remote_addr, &slot, &found);
+    assert(!found);
+
+    *get_record(slot) = temp_records[i];
+  }
+
+  Free(temp_records);
+}
+
+/* ================================================== */
+
+/* Procedure to add a new source */
+static NSR_Status
+add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, SourceParameters *params, int pool)
+{
+  SourceRecord *record;
+  int slot, found;
+
+  assert(initialised);
+
+  /* Find empty bin & check that we don't have the address already */
+  find_slot(remote_addr, &slot, &found);
+  if (found) {
+    return NSR_AlreadyInUse;
+  } else {
+    if (remote_addr->ip_addr.family != IPADDR_INET4 &&
+               remote_addr->ip_addr.family != IPADDR_INET6) {
+      return NSR_InvalidAF;
+    } else {
+      n_sources++;
+
+      if (!check_hashtable_size(n_sources, ARR_GetSize(records))) {
+        rehash_records();
+        find_slot(remote_addr, &slot, &found);
+      }
+
+      assert(!found);
+      record = get_record(slot);
+      record->data = NCR_GetInstance(remote_addr, type, params);
+      record->remote_addr = NCR_GetRemoteAddress(record->data);
+      record->name = name ? Strdup(name) : NULL;
+      record->pool = pool;
+      record->tentative = 1;
+
+      if (auto_start_sources)
+        NCR_StartInstance(record->data);
+
+      return NSR_Success;
+    }
+  }
+}
+
+/* ================================================== */
+
+static NSR_Status
+replace_source(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr)
+{
+  int slot1, slot2, found;
+  SourceRecord *record;
+  struct SourcePool *pool;
+
+  find_slot(old_addr, &slot1, &found);
+  if (!found)
+    return NSR_NoSuchSource;
+
+  find_slot(new_addr, &slot2, &found);
+  if (found)
+    return NSR_AlreadyInUse;
+
+  record = get_record(slot1);
+  NCR_ChangeRemoteAddress(record->data, new_addr);
+  record->remote_addr = NCR_GetRemoteAddress(record->data);
+
+  if (!record->tentative) {
+    record->tentative = 1;
+
+    if (record->pool != INVALID_POOL) {
+      pool = ARR_GetElement(pools, record->pool);
+      pool->sources--;
+    }
+  }
+
+  /* The hash table must be rebuilt for the new address */
+  rehash_records();
+
+  LOG(LOGS_INFO, "Source %s replaced with %s",
+      UTI_IPToString(&old_addr->ip_addr),
+      UTI_IPToString(&new_addr->ip_addr));
+
+  return NSR_Success;
+}
+
+/* ================================================== */
+
+static void
+process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs)
+{
+  NTP_Remote_Address address;
+  int i, added;
+  unsigned short first = 0;
+
+  if (us->random_order)
+    UTI_GetRandomBytes(&first, sizeof (first));
+
+  for (i = added = 0; i < n_addrs; i++) {
+    address.ip_addr = ip_addrs[((unsigned int)i + first) % n_addrs];
+    address.port = us->port;
+
+    DEBUG_LOG("(%d) %s", i + 1, UTI_IPToString(&address.ip_addr));
+
+    if (us->replacement) {
+      if (replace_source(&us->replace_source, &address) != NSR_AlreadyInUse)
+        break;
+    } else {
+      if (add_source(&address, us->name, us->new_source.type, &us->new_source.params,
+                     us->new_source.pool) == NSR_Success)
+        added++;
+
+      if (added >= us->new_source.max_new_sources)
+        break;
+    }
+  }
+}
+
+/* ================================================== */
+
+static void
+name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *anything)
+{
+  struct UnresolvedSource *us, **i, *next;
+
+  us = (struct UnresolvedSource *)anything;
+
+  assert(us == resolving_source);
+
+  DEBUG_LOG("%s resolved to %d addrs", us->name, n_addrs);
+
+  switch (status) {
+    case DNS_TryAgain:
+      break;
+    case DNS_Success:
+      process_resolved_name(us, ip_addrs, n_addrs);
+      break;
+    case DNS_Failure:
+      LOG(LOGS_WARN, "Invalid host %s", us->name);
+      break;
+    default:
+      assert(0);
+  }
+
+  next = us->next;
+
+  /* Remove the source from the list on success or failure, replacements
+     are removed on any status */
+  if (us->replacement || status != DNS_TryAgain) {
+    for (i = &unresolved_sources; *i; i = &(*i)->next) {
+      if (*i == us) {
+        *i = us->next;
+        Free(us->name);
+        Free(us);
+        break;
+      }
+    }
+  }
+
+  resolving_source = next;
+
+  if (next) {
+    /* Continue with the next source in the list */
+    DEBUG_LOG("resolving %s", next->name);
+    DNS_Name2IPAddressAsync(next->name, name_resolve_handler, next);
+  } else {
+    /* This was the last source in the list. If some sources couldn't
+       be resolved, try again in exponentially increasing interval. */
+    if (unresolved_sources) {
+      if (resolving_interval < MIN_RESOLVE_INTERVAL)
+        resolving_interval = MIN_RESOLVE_INTERVAL;
+      else if (resolving_interval < MAX_RESOLVE_INTERVAL)
+        resolving_interval++;
+      resolving_id = SCH_AddTimeoutByDelay(RESOLVE_INTERVAL_UNIT *
+          (1 << resolving_interval), resolve_sources, NULL);
+    } else {
+      resolving_interval = 0;
+    }
+
+    /* This round of resolving is done */
+    if (resolving_end_handler)
+      (resolving_end_handler)();
+  }
+}
+
+/* ================================================== */
+
+static void
+resolve_sources(void *arg)
+{
+  struct UnresolvedSource *us;
+
+  assert(!resolving_source);
+
+  PRV_ReloadDNS();
+
+  /* Start with the first source in the list, name_resolve_handler
+     will iterate over the rest */
+  us = unresolved_sources;
+
+  resolving_source = us;
+  DEBUG_LOG("resolving %s", us->name);
+  DNS_Name2IPAddressAsync(us->name, name_resolve_handler, us);
+}
+
+/* ================================================== */
+
+static void
+append_unresolved_source(struct UnresolvedSource *us)
+{
+  struct UnresolvedSource **i;
+
+  for (i = &unresolved_sources; *i; i = &(*i)->next)
+    ;
+  *i = us;
+  us->next = NULL;
+}
+
+/* ================================================== */
+
+NSR_Status
+NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
+{
+  return add_source(remote_addr, NULL, type, params, INVALID_POOL);
+}
+
+/* ================================================== */
+
+void
+NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params)
+{
+  struct UnresolvedSource *us;
+  struct SourcePool *sp;
+  NTP_Remote_Address remote_addr;
+
+  /* If the name is an IP address, don't bother with full resolving now
+     or later when trying to replace the source */
+  if (UTI_StringToIP(name, &remote_addr.ip_addr)) {
+    remote_addr.port = port;
+    NSR_AddSource(&remote_addr, type, params);
+    return;
+  }
+
+  us = MallocNew(struct UnresolvedSource);
+  us->name = Strdup(name);
+  us->port = port;
+  us->random_order = 0;
+  us->replacement = 0;
+  us->new_source.type = type;
+  us->new_source.params = *params;
+
+  if (!pool) {
+    us->new_source.pool = INVALID_POOL;
+    us->new_source.max_new_sources = 1;
+  } else {
+    sp = (struct SourcePool *)ARR_GetNewElement(pools);
+    sp->sources = 0;
+    sp->max_sources = params->max_sources;
+    us->new_source.pool = ARR_GetSize(pools) - 1;
+    us->new_source.max_new_sources = MAX_POOL_SOURCES;
+  }
+
+  append_unresolved_source(us);
+}
+
+/* ================================================== */
+
+void
+NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler)
+{
+  resolving_end_handler = handler;
+}
+
+/* ================================================== */
+
+void
+NSR_ResolveSources(void)
+{
+  /* Try to resolve unresolved sources now */
+  if (unresolved_sources) {
+    /* Make sure no resolving is currently running */
+    if (!resolving_source) {
+      if (resolving_interval) {
+        SCH_RemoveTimeout(resolving_id);
+        resolving_interval--;
+      }
+      resolve_sources(NULL);
+    }
+  } else {
+    /* No unresolved sources, we are done */
+    if (resolving_end_handler)
+      (resolving_end_handler)();
+  }
+}
+
+/* ================================================== */
+
+void NSR_StartSources(void)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARR_GetSize(records); i++) {
+    if (!get_record(i)->remote_addr)
+      continue;
+    NCR_StartInstance(get_record(i)->data);
+  }
+}
+
+/* ================================================== */
+
+void NSR_AutoStartSources(void)
+{
+  auto_start_sources = 1;
+}
+
+/* ================================================== */
+
+static void
+clean_source_record(SourceRecord *record)
+{
+  assert(record->remote_addr);
+  record->remote_addr = NULL;
+  NCR_DestroyInstance(record->data);
+  if (record->name)
+    Free(record->name);
+
+  n_sources--;
+}
+
+/* ================================================== */
+
+/* Procedure to remove a source.  We don't bother whether the port
+   address is matched - we're only interested in removing a record for
+   the right IP address.  Thus the caller can specify the port number
+   as zero if it wishes. */
+NSR_Status
+NSR_RemoveSource(NTP_Remote_Address *remote_addr)
+{
+  int slot, found;
+
+  assert(initialised);
+
+  find_slot(remote_addr, &slot, &found);
+  if (!found) {
+    return NSR_NoSuchSource;
+  }
+
+  clean_source_record(get_record(slot));
+
+  /* Rehash the table to make sure there are no broken probe sequences.
+     This is costly, but it's not expected to happen frequently. */
+
+  rehash_records();
+
+  return NSR_Success;
+}
+
+/* ================================================== */
+
+void
+NSR_RemoveAllSources(void)
+{
+  SourceRecord *record;
+  unsigned int i;
+
+  for (i = 0; i < ARR_GetSize(records); i++) {
+    record = get_record(i);
+    if (!record->remote_addr)
+      continue;
+    clean_source_record(record);
+  }
+
+  rehash_records();
+}
+
+/* ================================================== */
+
+static void
+resolve_source_replacement(SourceRecord *record)
+{
+  struct UnresolvedSource *us;
+
+  DEBUG_LOG("trying to replace %s", UTI_IPToString(&record->remote_addr->ip_addr));
+
+  us = MallocNew(struct UnresolvedSource);
+  us->name = Strdup(record->name);
+  us->port = record->remote_addr->port;
+  /* If there never was a valid reply from this source (e.g. it was a bad
+     replacement), ignore the order of addresses from the resolver to not get
+     stuck to a pair of addresses if the order doesn't change, or a group of
+     IPv4/IPv6 addresses if the resolver prefers inaccessible IP family */
+  us->random_order = record->tentative;
+  us->replacement = 1;
+  us->replace_source = *record->remote_addr;
+
+  append_unresolved_source(us);
+  NSR_ResolveSources();
+}
+
+/* ================================================== */
+
+void
+NSR_HandleBadSource(IPAddr *address)
+{
+  static struct timespec last_replacement;
+  struct timespec now;
+  NTP_Remote_Address remote_addr;
+  SourceRecord *record;
+  int slot, found;
+  double diff;
+
+  remote_addr.ip_addr = *address;
+  remote_addr.port = 0;
+
+  find_slot(&remote_addr, &slot, &found);
+  if (!found)
+    return;
+
+  record = get_record(slot);
+
+  /* Only sources with a name can be replaced */
+  if (!record->name)
+    return;
+
+  /* Don't resolve names too frequently */
+  SCH_GetLastEventTime(NULL, NULL, &now);
+  diff = UTI_DiffTimespecsToDouble(&now, &last_replacement);
+  if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_REPLACEMENT_INTERVAL)) {
+    DEBUG_LOG("replacement postponed");
+    return;
+  }
+  last_replacement = now;
+
+  resolve_source_replacement(record);
+}
+
+/* ================================================== */
+
+void
+NSR_RefreshAddresses(void)
+{
+  SourceRecord *record;
+  unsigned int i;
+
+  for (i = 0; i < ARR_GetSize(records); i++) {
+    record = get_record(i);
+    if (!record->remote_addr || !record->name)
+      continue;
+
+    resolve_source_replacement(record);
+  }
+}
+
+/* ================================================== */
+
+static void remove_tentative_pool_sources(int pool)
+{
+  SourceRecord *record;
+  unsigned int i, removed;
+
+  for (i = removed = 0; i < ARR_GetSize(records); i++) {
+    record = get_record(i);
+
+    if (!record->remote_addr || record->pool != pool || !record->tentative)
+      continue;
+
+    DEBUG_LOG("removing tentative source %s",
+              UTI_IPToString(&record->remote_addr->ip_addr));
+
+    clean_source_record(record);
+    removed++;
+  }
+
+  if (removed)
+    rehash_records();
+}
+
+/* ================================================== */
+
+uint32_t
+NSR_GetLocalRefid(IPAddr *address)
+{
+  NTP_Remote_Address remote_addr;
+  int slot, found;
+
+  remote_addr.ip_addr = *address;
+  remote_addr.port = 0;
+
+  find_slot(&remote_addr, &slot, &found);
+  if (!found)
+    return 0;
+
+  return NCR_GetLocalRefid(get_record(slot)->data);
+}
+
+/* ================================================== */
+
+/* This routine is called by ntp_io when a new packet arrives off the network,
+   possibly with an authentication tail */
+void
+NSR_ProcessRx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
+              NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
+{
+  SourceRecord *record;
+  struct SourcePool *pool;
+  int slot, found;
+
+  assert(initialised);
+
+  find_slot(remote_addr, &slot, &found);
+  if (found == 2) { /* Must match IP address AND port number */
+    record = get_record(slot);
+
+    if (!NCR_ProcessRxKnown(record->data, local_addr, rx_ts, message, length))
+      return;
+
+    if (record->tentative) {
+      /* This was the first good reply from the source */
+      record->tentative = 0;
+
+      if (record->pool != INVALID_POOL) {
+        pool = ARR_GetElement(pools, record->pool);
+        pool->sources++;
+
+        DEBUG_LOG("pool %s has %d confirmed sources", record->name, pool->sources);
+
+        /* If the number of sources from the pool reached the configured
+           maximum, remove the remaining tentative sources */
+        if (pool->sources >= pool->max_sources)
+          remove_tentative_pool_sources(record->pool);
+      }
+    }
+  } else {
+    NCR_ProcessRxUnknown(remote_addr, local_addr, rx_ts, message, length);
+  }
+}
+
+/* ================================================== */
+
+void
+NSR_ProcessTx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
+              NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length)
+{
+  SourceRecord *record;
+  int slot, found;
+
+  find_slot(remote_addr, &slot, &found);
+
+  if (found == 2) { /* Must match IP address AND port number */
+    record = get_record(slot);
+    NCR_ProcessTxKnown(record->data, local_addr, tx_ts, message, length);
+  } else {
+    NCR_ProcessTxUnknown(remote_addr, local_addr, tx_ts, message, length);
+  }
+}
+
+/* ================================================== */
+
+static void
+slew_sources(struct timespec *raw,
+             struct timespec *cooked,
+             double dfreq,
+             double doffset,
+             LCL_ChangeType change_type,
+             void *anything)
+{
+  SourceRecord *record;
+  unsigned int i;
+
+  for (i = 0; i < ARR_GetSize(records); i++) {
+    record = get_record(i);
+    if (record->remote_addr) {
+      if (change_type == LCL_ChangeUnknownStep) {
+        NCR_ResetInstance(record->data);
+        NCR_ResetPoll(record->data);
+      } else {
+        NCR_SlewTimes(record->data, cooked, dfreq, doffset);
+      }
+    }
+  }
+}
+
+/* ================================================== */
+
+int
+NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
+{
+  SourceRecord *record;
+  unsigned int i;
+  int any;
+
+  NSR_ResolveSources();
+
+  any = 0;
+  for (i = 0; i < ARR_GetSize(records); i++) {
+    record = get_record(i);
+    if (record->remote_addr) {
+      if (address->family == IPADDR_UNSPEC ||
+          !UTI_CompareIPs(&record->remote_addr->ip_addr, address, mask)) {
+        any = 1;
+        NCR_TakeSourceOnline(record->data);
+      }
+    }
+  }
+
+  if (address->family == IPADDR_UNSPEC) {
+    struct UnresolvedSource *us;
+
+    for (us = unresolved_sources; us; us = us->next) {
+      if (us->replacement)
+        continue;
+      any = 1;
+      us->new_source.params.online = 1;
+    }
+  }
+
+  return any;
+}
+
+/* ================================================== */
+
+int
+NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address)
+{
+  SourceRecord *record, *syncpeer;
+  unsigned int i, any;
+
+  any = 0;
+  syncpeer = NULL;
+  for (i = 0; i < ARR_GetSize(records); i++) {
+    record = get_record(i);
+    if (record->remote_addr) {
+      if (address->family == IPADDR_UNSPEC ||
+          !UTI_CompareIPs(&record->remote_addr->ip_addr, address, mask)) {
+        any = 1;
+        if (NCR_IsSyncPeer(record->data)) {
+          syncpeer = record;
+          continue;
+        }
+        NCR_TakeSourceOffline(record->data);
+      }
+    }
+  }
+
+  /* Take sync peer offline as last to avoid reference switching */
+  if (syncpeer) {
+    NCR_TakeSourceOffline(syncpeer->data);
+  }
+
+  if (address->family == IPADDR_UNSPEC) {
+    struct UnresolvedSource *us;
+
+    for (us = unresolved_sources; us; us = us->next) {
+      if (us->replacement)
+        continue;
+      any = 1;
+      us->new_source.params.online = 0;
+    }
+  }
+
+  return any;
+}
+
+/* ================================================== */
+
+int
+NSR_ModifyMinpoll(IPAddr *address, int new_minpoll)
+{
+  int slot, found;
+  NTP_Remote_Address addr;
+  addr.ip_addr = *address;
+  addr.port = 0;
+
+  find_slot(&addr, &slot, &found);
+  if (found == 0) {
+    return 0;
+  } else {
+    NCR_ModifyMinpoll(get_record(slot)->data, new_minpoll);
+    return 1;
+  }
+}
+
+/* ================================================== */
+
+int
+NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll)
+{
+  int slot, found;
+  NTP_Remote_Address addr;
+  addr.ip_addr = *address;
+  addr.port = 0;
+
+  find_slot(&addr, &slot, &found);
+  if (found == 0) {
+    return 0;
+  } else {
+    NCR_ModifyMaxpoll(get_record(slot)->data, new_maxpoll);
+    return 1;
+  }
+}
+
+/* ================================================== */
+
+int
+NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay)
+{
+  int slot, found;
+  NTP_Remote_Address addr;
+  addr.ip_addr = *address;
+  addr.port = 0;
+
+  find_slot(&addr, &slot, &found);
+  if (found == 0) {
+    return 0;
+  } else {
+    NCR_ModifyMaxdelay(get_record(slot)->data, new_max_delay);
+    return 1;
+  }
+}
+
+/* ================================================== */
+
+int
+NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio)
+{
+  int slot, found;
+  NTP_Remote_Address addr;
+  addr.ip_addr = *address;
+  addr.port = 0;
+
+  find_slot(&addr, &slot, &found);
+  if (found == 0) {
+    return 0;
+  } else {
+    NCR_ModifyMaxdelayratio(get_record(slot)->data, new_max_delay_ratio);
+    return 1;
+  }
+}
+
+/* ================================================== */
+
+int
+NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio)
+{
+  int slot, found;
+  NTP_Remote_Address addr;
+  addr.ip_addr = *address;
+  addr.port = 0;
+
+  find_slot(&addr, &slot, &found);
+  if (found == 0) {
+    return 0;
+  } else {
+    NCR_ModifyMaxdelaydevratio(get_record(slot)->data, new_max_delay_dev_ratio);
+    return 1;
+  }
+}
+
+/* ================================================== */
+
+int
+NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum)
+{
+  int slot, found;
+  NTP_Remote_Address addr;
+  addr.ip_addr = *address;
+  addr.port = 0;
+
+  find_slot(&addr, &slot, &found);
+  if (found == 0) {
+    return 0;
+  } else {
+    NCR_ModifyMinstratum(get_record(slot)->data, new_min_stratum);
+    return 1;
+  }
+}
+
+/* ================================================== */
+
+int
+NSR_ModifyPolltarget(IPAddr *address, int new_poll_target)
+{
+  int slot, found;
+  NTP_Remote_Address addr;
+  addr.ip_addr = *address;
+  addr.port = 0;
+
+  find_slot(&addr, &slot, &found);
+  if (found == 0) {
+    return 0;
+  } else {
+    NCR_ModifyPolltarget(get_record(slot)->data, new_poll_target);
+    return 1;
+  }
+}
+
+/* ================================================== */
+
+int
+NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples,
+                        IPAddr *mask, IPAddr *address)
+{
+  SourceRecord *record;
+  unsigned int i;
+  int any;
+
+  any = 0;
+  for (i = 0; i < ARR_GetSize(records); i++) {
+    record = get_record(i);
+    if (record->remote_addr) {
+      if (address->family == IPADDR_UNSPEC ||
+          !UTI_CompareIPs(&record->remote_addr->ip_addr, address, mask)) {
+        any = 1;
+        NCR_InitiateSampleBurst(record->data, n_good_samples, n_total_samples);
+      }
+    }
+  }
+
+  return any;
+
+}
+
+/* ================================================== */
+/* The ip address is assumed to be completed on input, that is how we
+   identify the source record. */
+
+void
+NSR_ReportSource(RPT_SourceReport *report, struct timespec *now)
+{
+  NTP_Remote_Address rem_addr;
+  int slot, found;
+
+  rem_addr.ip_addr = report->ip_addr;
+  rem_addr.port = 0;
+  find_slot(&rem_addr, &slot, &found);
+  if (found) {
+    NCR_ReportSource(get_record(slot)->data, report, now);
+  } else {
+    report->poll = 0;
+    report->latest_meas_ago = 0;
+  }
+}
+
+/* ================================================== */
+/* The ip address is assumed to be completed on input, that is how we
+   identify the source record. */
+
+int
+NSR_GetNTPReport(RPT_NTPReport *report)
+{
+  NTP_Remote_Address rem_addr;
+  int slot, found;
+
+  rem_addr.ip_addr = report->remote_addr;
+  rem_addr.port = 0;
+  find_slot(&rem_addr, &slot, &found);
+  if (!found)
+    return 0;
+
+  NCR_GetNTPReport(get_record(slot)->data, report);
+  return 1;
+}
+
+/* ================================================== */
+
+void
+NSR_GetActivityReport(RPT_ActivityReport *report)
+{
+  SourceRecord *record;
+  unsigned int i;
+  struct UnresolvedSource *us;
+
+  report->online = 0;
+  report->offline = 0;
+  report->burst_online = 0;
+  report->burst_offline = 0;
+
+  for (i = 0; i < ARR_GetSize(records); i++) {
+    record = get_record(i);
+    if (record->remote_addr) {
+      NCR_IncrementActivityCounters(record->data, &report->online, &report->offline,
+                                    &report->burst_online, &report->burst_offline);
+    }
+  }
+
+  report->unresolved = 0;
+
+  for (us = unresolved_sources; us; us = us->next) {
+    report->unresolved++;
+  }
+}
+
+
+/* ================================================== */
+
diff --git a/chrony_3_3/ntp_sources.h b/chrony_3_3/ntp_sources.h
new file mode 100644
index 0000000..23e9612
--- /dev/null
+++ b/chrony_3_3/ntp_sources.h
@@ -0,0 +1,136 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2002
+ * 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 for the part of the software that deals with the set of
+  current NTP servers and peers, which can resolve an IP address into
+  a source record for further processing.
+
+  */
+
+#ifndef GOT_NTP_SOURCES_H
+#define GOT_NTP_SOURCES_H
+
+#include "ntp.h"
+#include "addressing.h"
+#include "srcparams.h"
+#include "ntp_core.h"
+#include "reports.h"
+
+/* Status values returned by operations that indirectly result from user
+   input. */
+typedef enum {
+  NSR_Success, /* Operation successful */
+  NSR_NoSuchSource, /* Remove - attempt to remove a source that is not known */
+  NSR_AlreadyInUse, /* AddSource - attempt to add a source that is already known */ 
+  NSR_TooManySources, /* AddSource - too many sources already present */
+  NSR_InvalidAF /* AddSource - attempt to add a source with invalid address family */
+} NSR_Status;
+
+/* Procedure to add a new server or peer source. */
+extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
+
+/* Procedure to add a new server, peer source, or pool of servers specified by
+   name instead of address.  The name is resolved in exponentially increasing
+   intervals until it succeeds or fails with a non-temporary error. */
+extern void NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params);
+
+/* Function type for handlers to be called back when an attempt
+ * (possibly unsuccessful) to resolve unresolved sources ends */
+typedef void (*NSR_SourceResolvingEndHandler)(void);
+
+/* Set the handler, or NULL to disable the notification */
+extern void NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler);
+
+/* Procedure to start resolving unresolved sources */
+extern void NSR_ResolveSources(void);
+
+/* Procedure to start all sources */
+extern void NSR_StartSources(void);
+
+/* Start new sources automatically */
+extern void NSR_AutoStartSources(void);
+
+/* Procedure to remove a source */
+extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
+
+/* Procedure to remove all sources */
+extern void NSR_RemoveAllSources(void);
+
+/* Procedure to try to find a replacement for a bad source */
+extern void NSR_HandleBadSource(IPAddr *address);
+
+/* Procedure to resolve all names again */
+extern void NSR_RefreshAddresses(void);
+
+/* Procedure to get local reference ID corresponding to a source */
+extern uint32_t NSR_GetLocalRefid(IPAddr *address);
+
+/* This routine is called by ntp_io when a new packet arrives off the network */
+extern void NSR_ProcessRx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
+                          NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length);
+
+/* This routine is called by ntp_io when a packet was sent to the network and
+   an accurate transmit timestamp was captured */
+extern void NSR_ProcessTx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
+                          NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length);
+
+/* Initialisation function */
+extern void NSR_Initialise(void);
+
+/* Finalisation function */
+extern void NSR_Finalise(void);
+
+/* This routine is used to indicate that sources whose IP addresses
+   match a particular subnet should be set online again.  Returns a
+   flag indicating whether any hosts matched the address */
+extern int NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address);
+
+/* This routine is used to indicate that sources whose IP addresses
+   match a particular subnet should be set offline.  Returns a flag
+   indicating whether any hosts matched the address */
+extern int NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address);
+
+extern int NSR_ModifyMinpoll(IPAddr *address, int new_minpoll);
+
+extern int NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll);
+
+extern int NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay);
+
+extern int NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio);
+
+extern int NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_ratio);
+
+extern int NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum);
+
+extern int NSR_ModifyPolltarget(IPAddr *address, int new_poll_target);
+
+extern int NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, IPAddr *mask, IPAddr *address);
+
+extern void NSR_ReportSource(RPT_SourceReport *report, struct timespec *now);
+
+extern int NSR_GetNTPReport(RPT_NTPReport *report);
+
+extern void NSR_GetActivityReport(RPT_ActivityReport *report);
+
+#endif /* GOT_NTP_SOURCES_H */
diff --git a/chrony_3_3/pktlength.c b/chrony_3_3/pktlength.c
new file mode 100644
index 0000000..14a43f7
--- /dev/null
+++ b/chrony_3_3/pktlength.c
@@ -0,0 +1,204 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2002
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Routines to compute the expected length of a command or reply packet.
+  These operate on the RAW NETWORK packets, from the point of view of
+  integer endianness within the structures.
+
+  */
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "util.h"
+#include "pktlength.h"
+
+#define PADDING_LENGTH_(request_length, reply_length) \
+  (uint16_t)((request_length) < (reply_length) ? (reply_length) - (request_length) : 0)
+
+#define PADDING_LENGTH(request_data, reply_data) \
+  PADDING_LENGTH_(offsetof(CMD_Request, request_data), offsetof(CMD_Reply, reply_data))
+
+#define REQ_LENGTH_ENTRY(request_data_field, reply_data_field) \
+  { offsetof(CMD_Request, data.request_data_field.EOR), \
+    PADDING_LENGTH(data.request_data_field.EOR, data.reply_data_field.EOR) }
+
+#define RPY_LENGTH_ENTRY(reply_data_field) \
+  offsetof(CMD_Reply, data.reply_data_field.EOR)
+
+/* ================================================== */
+
+struct request_length {
+  uint16_t command;
+  uint16_t padding;
+};
+
+static const struct request_length request_lengths[] = {
+  REQ_LENGTH_ENTRY(null, null),                 /* NULL */
+  REQ_LENGTH_ENTRY(online, null),               /* ONLINE */
+  REQ_LENGTH_ENTRY(offline, null),              /* OFFLINE */
+  REQ_LENGTH_ENTRY(burst, null),                /* BURST */
+  REQ_LENGTH_ENTRY(modify_minpoll, null),       /* MODIFY_MINPOLL */
+  REQ_LENGTH_ENTRY(modify_maxpoll, null),       /* MODIFY_MAXPOLL */
+  REQ_LENGTH_ENTRY(dump, null),                 /* DUMP */
+  REQ_LENGTH_ENTRY(modify_maxdelay, null),      /* MODIFY_MAXDELAY */
+  REQ_LENGTH_ENTRY(modify_maxdelayratio, null), /* MODIFY_MAXDELAYRATIO */
+  REQ_LENGTH_ENTRY(modify_maxupdateskew, null), /* MODIFY_MAXUPDATESKEW */
+  REQ_LENGTH_ENTRY(logon, null),                /* LOGON */
+  REQ_LENGTH_ENTRY(settime, manual_timestamp),  /* SETTIME */
+  { 0, 0 },                                     /* LOCAL */
+  REQ_LENGTH_ENTRY(manual, null),               /* MANUAL */
+  REQ_LENGTH_ENTRY(null, n_sources),            /* N_SOURCES */
+  REQ_LENGTH_ENTRY(source_data, source_data),   /* SOURCE_DATA */
+  REQ_LENGTH_ENTRY(null, null),                 /* REKEY */
+  REQ_LENGTH_ENTRY(allow_deny, null),           /* ALLOW */
+  REQ_LENGTH_ENTRY(allow_deny, null),           /* ALLOWALL */
+  REQ_LENGTH_ENTRY(allow_deny, null),           /* DENY */
+  REQ_LENGTH_ENTRY(allow_deny, null),           /* DENYALL */
+  REQ_LENGTH_ENTRY(allow_deny, null),           /* CMDALLOW */
+  REQ_LENGTH_ENTRY(allow_deny, null),           /* CMDALLOWALL */
+  REQ_LENGTH_ENTRY(allow_deny, null),           /* CMDDENY */
+  REQ_LENGTH_ENTRY(allow_deny, null),           /* CMDDENYALL */
+  REQ_LENGTH_ENTRY(ac_check, null),             /* ACCHECK */
+  REQ_LENGTH_ENTRY(ac_check, null),             /* CMDACCHECK */
+  { 0, 0 },                                     /* ADD_SERVER */
+  { 0, 0 },                                     /* ADD_PEER */
+  REQ_LENGTH_ENTRY(del_source, null),           /* DEL_SOURCE */
+  REQ_LENGTH_ENTRY(null, null),                 /* WRITERTC */
+  REQ_LENGTH_ENTRY(dfreq, null),                /* DFREQ */
+  REQ_LENGTH_ENTRY(doffset, null),              /* DOFFSET */
+  REQ_LENGTH_ENTRY(null, tracking),             /* TRACKING */
+  REQ_LENGTH_ENTRY(sourcestats, sourcestats),   /* SOURCESTATS */
+  REQ_LENGTH_ENTRY(null, rtc),                  /* RTCREPORT */
+  REQ_LENGTH_ENTRY(null, null),                 /* TRIMRTC */
+  REQ_LENGTH_ENTRY(null, null),                 /* CYCLELOGS */
+  { 0, 0 },                                     /* SUBNETS_ACCESSED - not supported */
+  { 0, 0 },                                     /* CLIENT_ACCESSES - not supported */
+  { 0, 0 },                                     /* CLIENT_ACCESSES_BY_INDEX - not supported */
+  REQ_LENGTH_ENTRY(null, manual_list),          /* MANUAL_LIST */
+  REQ_LENGTH_ENTRY(manual_delete, null),        /* MANUAL_DELETE */
+  REQ_LENGTH_ENTRY(null, null),                 /* MAKESTEP */
+  REQ_LENGTH_ENTRY(null, activity),             /* ACTIVITY */
+  REQ_LENGTH_ENTRY(modify_minstratum, null),    /* MODIFY_MINSTRATUM */
+  REQ_LENGTH_ENTRY(modify_polltarget, null),    /* MODIFY_POLLTARGET */
+  REQ_LENGTH_ENTRY(modify_maxdelaydevratio, null), /* MODIFY_MAXDELAYDEVRATIO */
+  REQ_LENGTH_ENTRY(null, null),                 /* RESELECT */
+  REQ_LENGTH_ENTRY(reselect_distance, null),    /* RESELECTDISTANCE */
+  REQ_LENGTH_ENTRY(modify_makestep, null),      /* MODIFY_MAKESTEP */
+  REQ_LENGTH_ENTRY(null, smoothing),            /* SMOOTHING */
+  REQ_LENGTH_ENTRY(smoothtime, null),           /* SMOOTHTIME */
+  REQ_LENGTH_ENTRY(null, null),                 /* REFRESH */
+  REQ_LENGTH_ENTRY(null, server_stats),         /* SERVER_STATS */
+  REQ_LENGTH_ENTRY(client_accesses_by_index,
+                   client_accesses_by_index),   /* CLIENT_ACCESSES_BY_INDEX2 */
+  REQ_LENGTH_ENTRY(local, null),                /* LOCAL2 */
+  REQ_LENGTH_ENTRY(ntp_data, ntp_data),         /* NTP_DATA */
+  { 0, 0 },                                     /* ADD_SERVER2 */
+  { 0, 0 },                                     /* ADD_PEER2 */
+  REQ_LENGTH_ENTRY(ntp_source, null),           /* ADD_SERVER3 */
+  REQ_LENGTH_ENTRY(ntp_source, null),           /* ADD_PEER3 */
+  REQ_LENGTH_ENTRY(null, null),                 /* SHUTDOWN */
+};
+
+static const uint16_t reply_lengths[] = {
+  0,                                            /* empty slot */
+  RPY_LENGTH_ENTRY(null),                       /* NULL */
+  RPY_LENGTH_ENTRY(n_sources),                  /* N_SOURCES */
+  RPY_LENGTH_ENTRY(source_data),                /* SOURCE_DATA */
+  0,                                            /* MANUAL_TIMESTAMP */
+  RPY_LENGTH_ENTRY(tracking),                   /* TRACKING */
+  RPY_LENGTH_ENTRY(sourcestats),                /* SOURCESTATS */
+  RPY_LENGTH_ENTRY(rtc),                        /* RTC */
+  0,                                            /* SUBNETS_ACCESSED - not supported */
+  0,                                            /* CLIENT_ACCESSES - not supported */
+  0,                                            /* CLIENT_ACCESSES_BY_INDEX - not supported */
+  0,                                            /* MANUAL_LIST - not supported */
+  RPY_LENGTH_ENTRY(activity),                   /* ACTIVITY */
+  RPY_LENGTH_ENTRY(smoothing),                  /* SMOOTHING */
+  RPY_LENGTH_ENTRY(server_stats),               /* SERVER_STATS */
+  RPY_LENGTH_ENTRY(client_accesses_by_index),   /* CLIENT_ACCESSES_BY_INDEX2 */
+  RPY_LENGTH_ENTRY(ntp_data),                   /* NTP_DATA */
+  RPY_LENGTH_ENTRY(manual_timestamp),           /* MANUAL_TIMESTAMP2 */
+  RPY_LENGTH_ENTRY(manual_list),                /* MANUAL_LIST2 */
+};
+
+/* ================================================== */
+
+int
+PKL_CommandLength(CMD_Request *r)
+{
+  uint32_t type;
+  int command_length;
+
+  assert(sizeof (request_lengths) / sizeof (request_lengths[0]) == N_REQUEST_TYPES);
+
+  type = ntohs(r->command);
+  if (type >= N_REQUEST_TYPES)
+    return 0;
+
+  command_length = request_lengths[type].command;
+  if (!command_length)
+    return 0;
+
+  return command_length + PKL_CommandPaddingLength(r);
+}
+
+/* ================================================== */
+
+int
+PKL_CommandPaddingLength(CMD_Request *r)
+{
+  uint32_t type;
+
+  if (r->version < PROTO_VERSION_PADDING)
+    return 0;
+
+  type = ntohs(r->command);
+
+  if (type >= N_REQUEST_TYPES)
+    return 0;
+
+  return request_lengths[ntohs(r->command)].padding;
+}
+
+/* ================================================== */
+
+int
+PKL_ReplyLength(CMD_Reply *r)
+{
+  uint32_t type;
+
+  assert(sizeof (reply_lengths) / sizeof (reply_lengths[0]) == N_REPLY_TYPES);
+
+  type = ntohs(r->reply);
+
+  /* Note that reply type codes start from 1, not 0 */
+  if (type < 1 || type >= N_REPLY_TYPES)
+    return 0;
+
+  return reply_lengths[type];
+}
+
+/* ================================================== */
+
diff --git a/chrony_3_3/pktlength.h b/chrony_3_3/pktlength.h
new file mode 100644
index 0000000..fad4c30
--- /dev/null
+++ b/chrony_3_3/pktlength.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 for pktlength.c, routines for working out the expected length
+  of a network command/reply packet.
+
+  */
+
+#ifndef GOT_PKTLENGTH_H
+#define GOT_PKTLENGTH_H
+
+#include "candm.h"
+
+extern int PKL_CommandLength(CMD_Request *r);
+
+extern int PKL_CommandPaddingLength(CMD_Request *r);
+
+extern int PKL_ReplyLength(CMD_Reply *r);
+
+#endif /* GOT_PKTLENGTH_H */
diff --git a/chrony_3_3/privops.c b/chrony_3_3/privops.c
new file mode 100644
index 0000000..359e163
--- /dev/null
+++ b/chrony_3_3/privops.c
@@ -0,0 +1,731 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Bryan Christianson 2015
+ * Copyright (C) Miroslav Lichvar  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.
+ *
+ **********************************************************************
+
+  =======================================================================
+
+  Perform privileged operations over a unix socket to a privileged fork.
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "conf.h"
+#include "nameserv.h"
+#include "logging.h"
+#include "privops.h"
+#include "util.h"
+
+#define OP_ADJUSTTIME     1024
+#define OP_ADJUSTTIMEX    1025
+#define OP_SETTIME        1026
+#define OP_BINDSOCKET     1027
+#define OP_NAME2IPADDRESS 1028
+#define OP_RELOADDNS      1029
+#define OP_QUIT           1099
+
+union sockaddr_in46 {
+  struct sockaddr_in in4;
+#ifdef FEAT_IPV6
+  struct sockaddr_in6 in6;
+#endif
+  struct sockaddr u;
+};
+
+/* daemon request structs */
+
+typedef struct {
+  struct timeval tv;
+} ReqAdjustTime;
+
+#ifdef PRIVOPS_ADJUSTTIMEX
+typedef struct {
+  struct timex tmx;
+} ReqAdjustTimex;
+#endif
+
+typedef struct {
+  struct timeval tv;
+} ReqSetTime;
+
+typedef struct {
+  int sock;
+  socklen_t sa_len;
+  union sockaddr_in46 sa;
+} ReqBindSocket;
+
+typedef struct {
+  char name[256];
+} ReqName2IPAddress;
+
+typedef struct {
+  int op;
+  union {
+    ReqAdjustTime adjust_time;
+#ifdef PRIVOPS_ADJUSTTIMEX
+    ReqAdjustTimex adjust_timex;
+#endif
+    ReqSetTime set_time;
+    ReqBindSocket bind_socket;
+#ifdef PRIVOPS_NAME2IPADDRESS
+    ReqName2IPAddress name_to_ipaddress;
+#endif
+  } data;
+} PrvRequest;
+
+/* helper response structs */
+
+typedef struct {
+  struct timeval tv;
+} ResAdjustTime;
+
+#ifdef PRIVOPS_ADJUSTTIMEX
+typedef struct {
+  struct timex tmx;
+} ResAdjustTimex;
+#endif
+
+typedef struct {
+  IPAddr addresses[DNS_MAX_ADDRESSES];
+} ResName2IPAddress;
+
+typedef struct {
+  char msg[256];
+} ResFatalMsg;
+
+typedef struct {
+  int fatal_error;
+  int rc;
+  int res_errno;
+  union {
+    ResFatalMsg fatal_msg;
+    ResAdjustTime adjust_time;
+#ifdef PRIVOPS_ADJUSTTIMEX
+    ResAdjustTimex adjust_timex;
+#endif
+#ifdef PRIVOPS_NAME2IPADDRESS
+    ResName2IPAddress name_to_ipaddress;
+#endif
+  } data;
+} PrvResponse;
+
+static int helper_fd;
+static pid_t helper_pid;
+
+static int
+have_helper(void)
+{
+  return helper_fd >= 0;
+}
+
+/* ======================================================================= */
+
+/* HELPER - prepare fatal error for daemon */
+static void
+res_fatal(PrvResponse *res, const char *fmt, ...)
+{
+  va_list ap;
+
+  res->fatal_error = 1;
+  va_start(ap, fmt);
+  vsnprintf(res->data.fatal_msg.msg, sizeof (res->data.fatal_msg.msg), fmt, ap);
+  va_end(ap);
+}
+
+/* ======================================================================= */
+
+/* HELPER - send response to the fd */
+
+static int
+send_response(int fd, const PrvResponse *res)
+{
+  if (send(fd, res, sizeof (*res), 0) != sizeof (*res))
+    return 0;
+
+  return 1;
+}
+
+/* ======================================================================= */
+/* receive daemon request plus optional file descriptor over a unix socket */
+
+static int
+receive_from_daemon(int fd, PrvRequest *req)
+{
+  struct msghdr msg;
+  struct cmsghdr *cmsg;
+  struct iovec iov;
+  char cmsgbuf[256];
+
+  iov.iov_base = req;
+  iov.iov_len = sizeof (*req);
+
+  msg.msg_name = NULL;
+  msg.msg_namelen = 0;
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = (void *)cmsgbuf;
+  msg.msg_controllen = sizeof (cmsgbuf);
+  msg.msg_flags = MSG_WAITALL;
+
+  /* read the data */
+  if (recvmsg(fd, &msg, 0) != sizeof (*req))
+    return 0;
+
+  if (req->op == OP_BINDSOCKET) {
+    /* extract transferred descriptor */
+    req->data.bind_socket.sock = -1;
+    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+      if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+        memcpy(&req->data.bind_socket.sock, CMSG_DATA(cmsg), sizeof (int));
+    }
+
+    /* return error if valid descriptor not found */
+    if (req->data.bind_socket.sock < 0)
+      return 0;
+  }
+
+  return 1;
+}
+
+/* ======================================================================= */
+
+/* HELPER - perform adjtime() */
+
+#ifdef PRIVOPS_ADJUSTTIME
+static void
+do_adjust_time(const ReqAdjustTime *req, PrvResponse *res)
+{
+  res->rc = adjtime(&req->tv, &res->data.adjust_time.tv);
+  if (res->rc)
+    res->res_errno = errno;
+}
+#endif
+
+/* ======================================================================= */
+
+/* HELPER - perform ntp_adjtime() */
+
+#ifdef PRIVOPS_ADJUSTTIMEX
+static void
+do_adjust_timex(const ReqAdjustTimex *req, PrvResponse *res)
+{
+  res->data.adjust_timex.tmx = req->tmx;
+  res->rc = ntp_adjtime(&res->data.adjust_timex.tmx);
+  if (res->rc < 0)
+    res->res_errno = errno;
+}
+#endif
+
+/* ======================================================================= */
+
+/* HELPER - perform settimeofday() */
+
+#ifdef PRIVOPS_SETTIME
+static void
+do_set_time(const ReqSetTime *req, PrvResponse *res)
+{
+  res->rc = settimeofday(&req->tv, NULL);
+  if (res->rc)
+    res->res_errno = errno;
+}
+#endif
+
+/* ======================================================================= */
+
+/* HELPER - perform bind() */
+
+#ifdef PRIVOPS_BINDSOCKET
+static void
+do_bind_socket(ReqBindSocket *req, PrvResponse *res)
+{
+  unsigned short port;
+  IPAddr ip;
+  int sock_fd;
+  struct sockaddr *sa;
+  socklen_t sa_len;
+
+  sa = &req->sa.u;
+  sa_len = req->sa_len;
+  sock_fd = req->sock;
+
+  UTI_SockaddrToIPAndPort(sa, &ip, &port);
+  if (port && port != CNF_GetNTPPort() && port != CNF_GetAcquisitionPort()) {
+    close(sock_fd);
+    res_fatal(res, "Invalid port %d", port);
+    return;
+  }
+
+  res->rc = bind(sock_fd, sa, sa_len);
+  if (res->rc)
+    res->res_errno = errno;
+
+  /* sock is still open on daemon side, but we're done with it in the helper */
+  close(sock_fd);
+}
+#endif
+
+/* ======================================================================= */
+
+/* HELPER - perform DNS_Name2IPAddress() */
+
+#ifdef PRIVOPS_NAME2IPADDRESS
+static void
+do_name_to_ipaddress(ReqName2IPAddress *req, PrvResponse *res)
+{
+  /* make sure the string is terminated */
+  req->name[sizeof (req->name) - 1] = '\0';
+
+  res->rc = DNS_Name2IPAddress(req->name, res->data.name_to_ipaddress.addresses,
+                               DNS_MAX_ADDRESSES);
+}
+#endif
+
+/* ======================================================================= */
+
+/* HELPER - perform DNS_Reload() */
+
+#ifdef PRIVOPS_RELOADDNS
+static void
+do_reload_dns(PrvResponse *res)
+{
+  DNS_Reload();
+  res->rc = 0;
+}
+#endif
+
+/* ======================================================================= */
+
+/* HELPER - main loop - action requests from the daemon */
+
+static void
+helper_main(int fd)
+{
+  PrvRequest req;
+  PrvResponse res;
+  int quit = 0;
+
+  while (!quit) {
+    if (!receive_from_daemon(fd, &req))
+      /* read error or closed input - we cannot recover - give up */
+      break;
+
+    memset(&res, 0, sizeof (res));
+
+    switch (req.op) {
+#ifdef PRIVOPS_ADJUSTTIME
+      case OP_ADJUSTTIME:
+        do_adjust_time(&req.data.adjust_time, &res);
+        break;
+#endif
+#ifdef PRIVOPS_ADJUSTTIMEX
+      case OP_ADJUSTTIMEX:
+        do_adjust_timex(&req.data.adjust_timex, &res);
+        break;
+#endif
+#ifdef PRIVOPS_SETTIME
+      case OP_SETTIME:
+        do_set_time(&req.data.set_time, &res);
+        break;
+#endif
+#ifdef PRIVOPS_BINDSOCKET
+      case OP_BINDSOCKET:
+        do_bind_socket(&req.data.bind_socket, &res);
+        break;
+#endif
+#ifdef PRIVOPS_NAME2IPADDRESS
+      case OP_NAME2IPADDRESS:
+        do_name_to_ipaddress(&req.data.name_to_ipaddress, &res);
+        break;
+#endif
+#ifdef PRIVOPS_RELOADDNS
+      case OP_RELOADDNS:
+        do_reload_dns(&res);
+        break;
+#endif
+      case OP_QUIT:
+        quit = 1;
+        continue;
+
+      default:
+        res_fatal(&res, "Unexpected operator %d", req.op);
+        break;
+    }
+
+    send_response(fd, &res);
+  }
+
+  close(fd);
+  exit(0);
+}
+
+/* ======================================================================= */
+
+/* DAEMON - receive helper response */
+
+static void
+receive_response(PrvResponse *res)
+{
+  int resp_len;
+
+  resp_len = recv(helper_fd, res, sizeof (*res), 0);
+  if (resp_len < 0)
+    LOG_FATAL("Could not read from helper : %s", strerror(errno));
+  if (resp_len != sizeof (*res))
+    LOG_FATAL("Invalid helper response");
+
+  if (res->fatal_error)
+    LOG_FATAL("Error in helper : %s", res->data.fatal_msg.msg);
+
+  DEBUG_LOG("Received response rc=%d", res->rc);
+
+  /* if operation failed in the helper, set errno so daemon can print log message */
+  if (res->res_errno)
+    errno = res->res_errno;
+}
+
+/* ======================================================================= */
+
+/* DAEMON - send daemon request to the helper */
+
+static void
+send_request(PrvRequest *req)
+{
+  struct msghdr msg;
+  struct iovec iov;
+  char cmsgbuf[256];
+
+  iov.iov_base = req;
+  iov.iov_len = sizeof (*req);
+
+  msg.msg_name = NULL;
+  msg.msg_namelen = 0;
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = NULL;
+  msg.msg_controllen = 0;
+  msg.msg_flags = 0;
+
+  if (req->op == OP_BINDSOCKET) {
+    /* send file descriptor as a control message */
+    struct cmsghdr *cmsg;
+    int *ptr_send_fd;
+
+    msg.msg_control = cmsgbuf;
+    msg.msg_controllen = CMSG_SPACE(sizeof (int));
+
+    cmsg = CMSG_FIRSTHDR(&msg);
+    memset(cmsg, 0, CMSG_SPACE(sizeof (int)));
+
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    cmsg->cmsg_len = CMSG_LEN(sizeof (int));
+
+    ptr_send_fd = (int *)CMSG_DATA(cmsg);
+    *ptr_send_fd = req->data.bind_socket.sock;
+  }
+
+  if (sendmsg(helper_fd, &msg, 0) < 0) {
+    /* don't try to send another request from exit() */
+    helper_fd = -1;
+    LOG_FATAL("Could not send to helper : %s", strerror(errno));
+  }
+
+  DEBUG_LOG("Sent request op=%d", req->op);
+}
+
+/* ======================================================================= */
+
+/* DAEMON - send daemon request and wait for response */
+
+static void
+submit_request(PrvRequest *req, PrvResponse *res)
+{
+  send_request(req);
+  receive_response(res);
+}
+
+/* ======================================================================= */
+
+/* DAEMON - send the helper a request to exit and wait until it exits */
+
+static void
+stop_helper(void)
+{
+  PrvRequest req;
+  int status;
+
+  if (!have_helper())
+    return;
+
+  memset(&req, 0, sizeof (req));
+  req.op = OP_QUIT;
+  send_request(&req);
+
+  waitpid(helper_pid, &status, 0);
+}
+
+/* ======================================================================= */
+
+/* DAEMON - request adjtime() */
+
+#ifdef PRIVOPS_ADJUSTTIME
+int
+PRV_AdjustTime(const struct timeval *delta, struct timeval *olddelta)
+{
+  PrvRequest req;
+  PrvResponse res;
+
+  if (!have_helper() || delta == NULL)
+    /* helper is not running or read adjustment call */
+    return adjtime(delta, olddelta);
+
+  memset(&req, 0, sizeof (req));
+  req.op = OP_ADJUSTTIME;
+  req.data.adjust_time.tv = *delta;
+
+  submit_request(&req, &res);
+
+  if (olddelta)
+    *olddelta = res.data.adjust_time.tv;
+
+  return res.rc;
+}
+#endif
+
+/* ======================================================================= */
+
+/* DAEMON - request ntp_adjtime() */
+
+#ifdef PRIVOPS_ADJUSTTIMEX
+int
+PRV_AdjustTimex(struct timex *tmx)
+{
+  PrvRequest req;
+  PrvResponse res;
+
+  if (!have_helper())
+    return ntp_adjtime(tmx);
+
+  memset(&req, 0, sizeof (req));
+  req.op = OP_ADJUSTTIMEX;
+  req.data.adjust_timex.tmx = *tmx;
+
+  submit_request(&req, &res);
+
+  *tmx = res.data.adjust_timex.tmx;
+
+  return res.rc;
+}
+#endif
+
+/* ======================================================================= */
+
+/* DAEMON - request settimeofday() */
+
+#ifdef PRIVOPS_SETTIME
+int
+PRV_SetTime(const struct timeval *tp, const struct timezone *tzp)
+{
+  PrvRequest req;
+  PrvResponse res;
+
+  /* only support setting the time */
+  assert(tp != NULL);
+  assert(tzp == NULL);
+
+  if (!have_helper())
+    return settimeofday(tp, NULL);
+
+  memset(&req, 0, sizeof (req));
+  req.op = OP_SETTIME;
+  req.data.set_time.tv = *tp;
+
+  submit_request(&req, &res);
+
+  return res.rc;
+}
+#endif
+
+/* ======================================================================= */
+
+/* DAEMON - request bind() */
+
+#ifdef PRIVOPS_BINDSOCKET
+int
+PRV_BindSocket(int sock, struct sockaddr *address, socklen_t address_len)
+{
+  PrvRequest req;
+  PrvResponse res;
+  IPAddr ip;
+  unsigned short port;
+
+  UTI_SockaddrToIPAndPort(address, &ip, &port);
+  if (port && port != CNF_GetNTPPort() && port != CNF_GetAcquisitionPort())
+    assert(0);
+
+  if (!have_helper())
+    return bind(sock, address, address_len);
+
+  memset(&req, 0, sizeof (req));
+  req.op = OP_BINDSOCKET;
+  req.data.bind_socket.sock = sock;
+  req.data.bind_socket.sa_len = address_len;
+  memcpy(&req.data.bind_socket.sa.u, address, address_len);
+
+  submit_request(&req, &res);
+
+  return res.rc;
+}
+#endif
+
+/* ======================================================================= */
+
+/* DAEMON - request DNS_Name2IPAddress() */
+
+#ifdef PRIVOPS_NAME2IPADDRESS
+int
+PRV_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
+{
+  PrvRequest req;
+  PrvResponse res;
+  int i;
+
+  if (!have_helper())
+    return DNS_Name2IPAddress(name, ip_addrs, max_addrs);
+
+  memset(&req, 0, sizeof (req));
+  req.op = OP_NAME2IPADDRESS;
+  if (snprintf(req.data.name_to_ipaddress.name, sizeof (req.data.name_to_ipaddress.name),
+               "%s", name) >= sizeof (req.data.name_to_ipaddress.name)) {
+    DEBUG_LOG("Name too long");
+    return DNS_Failure;
+  }
+
+  submit_request(&req, &res);
+
+  for (i = 0; i < max_addrs && i < DNS_MAX_ADDRESSES; i++)
+    ip_addrs[i] = res.data.name_to_ipaddress.addresses[i];
+
+  return res.rc;
+}
+#endif
+
+/* ======================================================================= */
+
+/* DAEMON - request res_init() */
+
+#ifdef PRIVOPS_RELOADDNS
+void
+PRV_ReloadDNS(void)
+{
+  PrvRequest req;
+  PrvResponse res;
+
+  if (!have_helper()) {
+    DNS_Reload();
+    return;
+  }
+
+  memset(&req, 0, sizeof (req));
+  req.op = OP_RELOADDNS;
+
+  submit_request(&req, &res);
+  assert(!res.rc);
+}
+#endif
+
+/* ======================================================================= */
+
+void
+PRV_Initialise(void)
+{
+  helper_fd = -1;
+}
+
+/* ======================================================================= */
+
+/* DAEMON - setup socket(s) then fork to run the helper */
+/* must be called before privileges are dropped */
+
+void
+PRV_StartHelper(void)
+{
+  pid_t pid;
+  int fd, sock_pair[2];
+
+  if (have_helper())
+    LOG_FATAL("Helper already running");
+
+  if (
+#ifdef SOCK_SEQPACKET
+      socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sock_pair) &&
+#endif
+      socketpair(AF_UNIX, SOCK_DGRAM, 0, sock_pair))
+    LOG_FATAL("socketpair() failed : %s", strerror(errno));
+
+  UTI_FdSetCloexec(sock_pair[0]);
+  UTI_FdSetCloexec(sock_pair[1]);
+
+  pid = fork();
+  if (pid < 0)
+    LOG_FATAL("fork() failed : %s", strerror(errno));
+
+  if (pid == 0) {
+    /* child process */
+    close(sock_pair[0]);
+
+    /* close other descriptors inherited from the parent process */
+    for (fd = 0; fd < 1024; fd++) {
+      if (fd != sock_pair[1])
+        close(fd);
+    }
+
+    /* ignore signals, the process will exit on OP_QUIT request */
+    UTI_SetQuitSignalsHandler(SIG_IGN);
+
+    helper_main(sock_pair[1]);
+
+  } else {
+    /* parent process */
+    close(sock_pair[1]);
+    helper_fd = sock_pair[0];
+    helper_pid = pid;
+
+    /* stop the helper even when not exiting cleanly from the main function */
+    atexit(stop_helper);
+  }
+}
+
+/* ======================================================================= */
+
+/* DAEMON - graceful shutdown of the helper */
+
+void
+PRV_Finalise(void)
+{
+  if (!have_helper())
+    return;
+
+  stop_helper();
+  close(helper_fd);
+  helper_fd = -1;
+}
diff --git a/chrony_3_3/privops.h b/chrony_3_3/privops.h
new file mode 100644
index 0000000..146580b
--- /dev/null
+++ b/chrony_3_3/privops.h
@@ -0,0 +1,77 @@
+/*
+  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.
+ *
+ **********************************************************************
+
+  =======================================================================
+
+  Perform privileged operations over a unix socket to a privileged fork.
+
+*/
+
+#ifndef GOT_PRIVOPS_H
+#define GOT_PRIVOPS_H
+
+#ifdef PRIVOPS_ADJUSTTIME
+int PRV_AdjustTime(const struct timeval *delta, struct timeval *olddelta);
+#else
+#define PRV_AdjustTime adjtime
+#endif
+
+#ifdef PRIVOPS_ADJUSTTIMEX
+int PRV_AdjustTimex(struct timex *txc);
+#else
+#define PRV_AdjustTimex ntp_adjtime
+#endif
+
+#ifdef PRIVOPS_SETTIME
+int PRV_SetTime(const struct timeval *tp, const struct timezone *tzp);
+#else
+#define PRV_SetTime settimeofday
+#endif
+
+#ifdef PRIVOPS_BINDSOCKET
+int PRV_BindSocket(int sock, struct sockaddr *address, socklen_t address_len);
+#else
+#define PRV_BindSocket bind
+#endif
+
+#ifdef PRIVOPS_NAME2IPADDRESS
+int PRV_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs);
+#else
+#define PRV_Name2IPAddress DNS_Name2IPAddress
+#endif
+
+#ifdef PRIVOPS_RELOADDNS
+void PRV_ReloadDNS(void);
+#else
+#define PRV_ReloadDNS DNS_Reload
+#endif
+
+#ifdef PRIVOPS_HELPER
+void PRV_Initialise(void);
+void PRV_StartHelper(void);
+void PRV_Finalise(void);
+#else
+#define PRV_Initialise()
+#define PRV_StartHelper()
+#define PRV_Finalise()
+#endif
+
+#endif
diff --git a/chrony_3_3/refclock.c b/chrony_3_3/refclock.c
new file mode 100644
index 0000000..0791d47
--- /dev/null
+++ b/chrony_3_3/refclock.c
@@ -0,0 +1,1050 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2009-2011, 2013-2014, 2016-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Routines implementing reference clocks.
+
+  */
+
+#include "config.h"
+
+#include "array.h"
+#include "refclock.h"
+#include "reference.h"
+#include "conf.h"
+#include "local.h"
+#include "memory.h"
+#include "util.h"
+#include "sources.h"
+#include "logging.h"
+#include "regress.h"
+#include "sched.h"
+
+/* list of refclock drivers */
+extern RefclockDriver RCL_SHM_driver;
+extern RefclockDriver RCL_SOCK_driver;
+extern RefclockDriver RCL_PPS_driver;
+extern RefclockDriver RCL_PHC_driver;
+
+struct FilterSample {
+  double offset;
+  double dispersion;
+  struct timespec sample_time;
+};
+
+struct MedianFilter {
+  int length;
+  int index;
+  int used;
+  int last;
+  int avg_var_n;
+  double avg_var;
+  double max_var;
+  struct FilterSample *samples;
+  int *selected;
+  double *x_data;
+  double *y_data;
+  double *w_data;
+};
+
+struct RCL_Instance_Record {
+  RefclockDriver *driver;
+  void *data;
+  char *driver_parameter;
+  int driver_parameter_length;
+  int driver_poll;
+  int driver_polled;
+  int poll;
+  int leap_status;
+  int pps_forced;
+  int pps_rate;
+  int pps_active;
+  int max_lock_age;
+  int stratum;
+  int tai;
+  struct MedianFilter filter;
+  uint32_t ref_id;
+  uint32_t lock_ref;
+  double offset;
+  double delay;
+  double precision;
+  double pulse_width;
+  SCH_TimeoutID timeout_id;
+  SRC_Instance source;
+};
+
+/* Array of pointers to RCL_Instance_Record */
+static ARR_Instance refclocks;
+
+static LOG_FileID logfileid;
+
+static int valid_sample_time(RCL_Instance instance, struct timespec *sample_time);
+static int pps_stratum(RCL_Instance instance, struct timespec *ts);
+static void poll_timeout(void *arg);
+static void slew_samples(struct timespec *raw, struct timespec *cooked, double dfreq,
+             double doffset, LCL_ChangeType change_type, void *anything);
+static void add_dispersion(double dispersion, void *anything);
+static void log_sample(RCL_Instance instance, struct timespec *sample_time, int filtered, int pulse, double raw_offset, double cooked_offset, double dispersion);
+
+static void filter_init(struct MedianFilter *filter, int length, double max_dispersion);
+static void filter_fini(struct MedianFilter *filter);
+static void filter_reset(struct MedianFilter *filter);
+static double filter_get_avg_sample_dispersion(struct MedianFilter *filter);
+static void filter_add_sample(struct MedianFilter *filter, struct timespec *sample_time, double offset, double dispersion);
+static int filter_get_last_sample(struct MedianFilter *filter, struct timespec *sample_time, double *offset, double *dispersion);
+static int filter_get_samples(struct MedianFilter *filter);
+static int filter_select_samples(struct MedianFilter *filter);
+static int filter_get_sample(struct MedianFilter *filter, struct timespec *sample_time, double *offset, double *dispersion);
+static void filter_slew_samples(struct MedianFilter *filter, struct timespec *when, double dfreq, double doffset);
+static void filter_add_dispersion(struct MedianFilter *filter, double dispersion);
+
+static RCL_Instance
+get_refclock(unsigned int index)
+{
+  return *(RCL_Instance *)ARR_GetElement(refclocks, index);
+}
+
+void
+RCL_Initialise(void)
+{
+  refclocks = ARR_CreateInstance(sizeof (RCL_Instance));
+
+  CNF_AddRefclocks();
+
+  if (ARR_GetSize(refclocks) > 0) {
+    LCL_AddParameterChangeHandler(slew_samples, NULL);
+    LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
+  }
+
+  logfileid = CNF_GetLogRefclocks() ? LOG_FileOpen("refclocks",
+      "   Date (UTC) Time         Refid  DP L P  Raw offset   Cooked offset      Disp.")
+    : -1;
+}
+
+void
+RCL_Finalise(void)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARR_GetSize(refclocks); i++) {
+    RCL_Instance inst = get_refclock(i);
+
+    if (inst->driver->fini)
+      inst->driver->fini(inst);
+
+    filter_fini(&inst->filter);
+    Free(inst->driver_parameter);
+    SRC_DestroyInstance(inst->source);
+    Free(inst);
+  }
+
+  if (ARR_GetSize(refclocks) > 0) {
+    LCL_RemoveParameterChangeHandler(slew_samples, NULL);
+    LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
+  }
+
+  ARR_DestroyInstance(refclocks);
+}
+
+int
+RCL_AddRefclock(RefclockParameters *params)
+{
+  RCL_Instance inst;
+
+  inst = MallocNew(struct RCL_Instance_Record);
+  *(RCL_Instance *)ARR_GetNewElement(refclocks) = inst;
+
+  if (strcmp(params->driver_name, "SHM") == 0) {
+    inst->driver = &RCL_SHM_driver;
+  } else if (strcmp(params->driver_name, "SOCK") == 0) {
+    inst->driver = &RCL_SOCK_driver;
+  } else if (strcmp(params->driver_name, "PPS") == 0) {
+    inst->driver = &RCL_PPS_driver;
+  } else if (strcmp(params->driver_name, "PHC") == 0) {
+    inst->driver = &RCL_PHC_driver;
+  } else {
+    LOG_FATAL("unknown refclock driver %s", params->driver_name);
+  }
+
+  if (!inst->driver->init && !inst->driver->poll)
+    LOG_FATAL("refclock driver %s is not compiled in", params->driver_name);
+
+  if (params->tai && !CNF_GetLeapSecTimezone())
+    LOG_FATAL("refclock tai option requires leapsectz");
+
+  inst->data = NULL;
+  inst->driver_parameter = params->driver_parameter;
+  inst->driver_parameter_length = 0;
+  inst->driver_poll = params->driver_poll;
+  inst->poll = params->poll;
+  inst->driver_polled = 0;
+  inst->leap_status = LEAP_Normal;
+  inst->pps_forced = params->pps_forced;
+  inst->pps_rate = params->pps_rate;
+  inst->pps_active = 0;
+  inst->max_lock_age = params->max_lock_age;
+  inst->stratum = params->stratum;
+  inst->tai = params->tai;
+  inst->lock_ref = params->lock_ref_id;
+  inst->offset = params->offset;
+  inst->delay = params->delay;
+  inst->precision = LCL_GetSysPrecisionAsQuantum();
+  inst->precision = MAX(inst->precision, params->precision);
+  inst->pulse_width = params->pulse_width;
+  inst->timeout_id = -1;
+  inst->source = NULL;
+
+  if (inst->driver_parameter) {
+    int i;
+
+    inst->driver_parameter_length = strlen(inst->driver_parameter);
+    for (i = 0; i < inst->driver_parameter_length; i++)
+      if (inst->driver_parameter[i] == ':')
+        inst->driver_parameter[i] = '\0';
+  }
+
+  if (inst->pps_rate < 1)
+    inst->pps_rate = 1;
+
+  if (params->ref_id)
+    inst->ref_id = params->ref_id;
+  else {
+    unsigned char ref[5] = { 0, 0, 0, 0, 0 };
+    unsigned int index = ARR_GetSize(refclocks) - 1;
+
+    snprintf((char *)ref, sizeof (ref), "%3.3s", params->driver_name);
+    ref[3] = index % 10 + '0';
+    if (index >= 10)
+      ref[2] = (index / 10) % 10 + '0';
+
+    inst->ref_id = (uint32_t)ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
+  }
+
+  if (inst->driver->poll) {
+    int max_samples;
+
+    if (inst->driver_poll > inst->poll)
+      inst->driver_poll = inst->poll;
+
+    max_samples = 1 << (inst->poll - inst->driver_poll);
+    if (max_samples < params->filter_length) {
+      if (max_samples < 4) {
+        LOG(LOGS_WARN, "Setting filter length for %s to %d",
+            UTI_RefidToString(inst->ref_id), max_samples);
+      }
+      params->filter_length = max_samples;
+    }
+  }
+
+  if (inst->driver->init && !inst->driver->init(inst))
+    LOG_FATAL("refclock %s initialisation failed", params->driver_name);
+
+  filter_init(&inst->filter, params->filter_length, params->max_dispersion);
+
+  inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_options, NULL,
+                                       params->min_samples, params->max_samples, 0.0, 0.0);
+
+  DEBUG_LOG("refclock %s refid=%s poll=%d dpoll=%d filter=%d",
+      params->driver_name, UTI_RefidToString(inst->ref_id),
+      inst->poll, inst->driver_poll, params->filter_length);
+
+  Free(params->driver_name);
+
+  return 1;
+}
+
+void
+RCL_StartRefclocks(void)
+{
+  unsigned int i, j, n;
+
+  n = ARR_GetSize(refclocks);
+
+  for (i = 0; i < n; i++) {
+    RCL_Instance inst = get_refclock(i);
+
+    SRC_SetActive(inst->source);
+    inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst);
+
+    if (inst->lock_ref) {
+      /* Replace lock refid with index to refclocks */
+      for (j = 0; j < n && get_refclock(j)->ref_id != inst->lock_ref; j++)
+        ;
+      inst->lock_ref = j < n ? j : -1;
+    } else
+      inst->lock_ref = -1;
+  }
+}
+
+void
+RCL_ReportSource(RPT_SourceReport *report, struct timespec *now)
+{
+  unsigned int i;
+  uint32_t ref_id;
+
+  assert(report->ip_addr.family == IPADDR_INET4);
+  ref_id = report->ip_addr.addr.in4;
+
+  for (i = 0; i < ARR_GetSize(refclocks); i++) {
+    RCL_Instance inst = get_refclock(i);
+    if (inst->ref_id == ref_id) {
+      report->poll = inst->poll;
+      report->mode = RPT_LOCAL_REFERENCE;
+      break;
+    }
+  }
+}
+
+void
+RCL_SetDriverData(RCL_Instance instance, void *data)
+{
+  instance->data = data;
+}
+
+void *
+RCL_GetDriverData(RCL_Instance instance)
+{
+  return instance->data;
+}
+
+char *
+RCL_GetDriverParameter(RCL_Instance instance)
+{
+  return instance->driver_parameter;
+}
+
+char *
+RCL_GetDriverOption(RCL_Instance instance, char *name)
+{
+  char *s, *e;
+  int n;
+
+  s = instance->driver_parameter;
+  e = s + instance->driver_parameter_length;
+  n = strlen(name);
+
+  while (1) {
+    s += strlen(s) + 1;
+    if (s >= e)
+      break;
+    if (!strncmp(name, s, n)) {
+      if (s[n] == '=')
+        return s + n + 1;
+      if (s[n] == '\0')
+        return s + n;
+    }
+  }
+
+  return NULL;
+}
+
+static int
+convert_tai_offset(struct timespec *sample_time, double *offset)
+{
+  struct timespec tai_ts, utc_ts;
+  int tai_offset;
+
+  /* Get approximate TAI-UTC offset for the reference time in TAI */
+  UTI_AddDoubleToTimespec(sample_time, *offset, &tai_ts);
+  tai_offset = REF_GetTaiOffset(&tai_ts);
+
+  /* Get TAI-UTC offset for the reference time in UTC +/- 1 second */
+  UTI_AddDoubleToTimespec(&tai_ts, -tai_offset, &utc_ts);
+  tai_offset = REF_GetTaiOffset(&utc_ts);
+
+  if (!tai_offset)
+    return 0;
+
+  *offset -= tai_offset;
+
+  return 1;
+}
+
+int
+RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap)
+{
+  double correction, dispersion;
+  struct timespec cooked_time;
+
+  if (instance->pps_forced)
+    return RCL_AddPulse(instance, sample_time, -offset);
+
+  LCL_GetOffsetCorrection(sample_time, &correction, &dispersion);
+  UTI_AddDoubleToTimespec(sample_time, correction, &cooked_time);
+  dispersion += instance->precision;
+
+  /* Make sure the timestamp and offset provided by the driver are sane */
+  if (!UTI_IsTimeOffsetSane(sample_time, offset) ||
+      !valid_sample_time(instance, &cooked_time))
+    return 0;
+
+  switch (leap) {
+    case LEAP_Normal:
+    case LEAP_InsertSecond:
+    case LEAP_DeleteSecond:
+      instance->leap_status = leap;
+      break;
+    default:
+      DEBUG_LOG("refclock sample ignored bad leap %d", leap);
+      return 0;
+  }
+
+  if (instance->tai && !convert_tai_offset(sample_time, &offset)) {
+    DEBUG_LOG("refclock sample ignored unknown TAI offset");
+    return 0;
+  }
+
+  filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset, dispersion);
+  instance->pps_active = 0;
+
+  log_sample(instance, &cooked_time, 0, 0, offset, offset - correction + instance->offset, dispersion);
+
+  /* for logging purposes */
+  if (!instance->driver->poll)
+    instance->driver_polled++;
+
+  return 1;
+}
+
+int
+RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second)
+{
+  double correction, dispersion;
+  struct timespec cooked_time;
+
+  LCL_GetOffsetCorrection(pulse_time, &correction, &dispersion);
+  UTI_AddDoubleToTimespec(pulse_time, correction, &cooked_time);
+  second += correction;
+
+  if (!UTI_IsTimeOffsetSane(pulse_time, 0.0))
+    return 0;
+
+  return RCL_AddCookedPulse(instance, &cooked_time, second, dispersion, correction);
+}
+
+static int
+check_pulse_edge(RCL_Instance instance, double offset, double distance)
+{
+  double max_error;
+
+  if (instance->pulse_width <= 0.0)
+    return 1;
+
+  max_error = 1.0 / instance->pps_rate - instance->pulse_width;
+  max_error = MIN(instance->pulse_width, max_error);
+  max_error *= 0.5;
+
+  if (fabs(offset) > max_error || distance > max_error) {
+      DEBUG_LOG("refclock pulse ignored offset=%.9f distance=%.9f max_error=%.9f",
+                offset, distance, max_error);
+      return 0;
+  }
+
+  return 1;
+}
+
+int
+RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
+                   double second, double dispersion, double raw_correction)
+{
+  double offset;
+  int rate;
+  NTP_Leap leap;
+
+  if (!UTI_IsTimeOffsetSane(cooked_time, second) ||
+      !valid_sample_time(instance, cooked_time))
+    return 0;
+
+  leap = LEAP_Normal;
+  dispersion += instance->precision;
+  rate = instance->pps_rate;
+
+  offset = -second + instance->offset;
+
+  /* Adjust the offset to [-0.5/rate, 0.5/rate) interval */
+  offset -= (long)(offset * rate) / (double)rate;
+  if (offset < -0.5 / rate)
+    offset += 1.0 / rate;
+  else if (offset >= 0.5 / rate)
+    offset -= 1.0 / rate;
+
+  if (instance->lock_ref != -1) {
+    RCL_Instance lock_refclock;
+    struct timespec ref_sample_time;
+    double sample_diff, ref_offset, ref_dispersion, shift;
+
+    lock_refclock = get_refclock(instance->lock_ref);
+
+    if (!filter_get_last_sample(&lock_refclock->filter,
+          &ref_sample_time, &ref_offset, &ref_dispersion)) {
+      DEBUG_LOG("refclock pulse ignored no ref sample");
+      return 0;
+    }
+
+    ref_dispersion += filter_get_avg_sample_dispersion(&lock_refclock->filter);
+
+    sample_diff = UTI_DiffTimespecsToDouble(cooked_time, &ref_sample_time);
+    if (fabs(sample_diff) >= (double)instance->max_lock_age / rate) {
+      DEBUG_LOG("refclock pulse ignored samplediff=%.9f",
+          sample_diff);
+      return 0;
+    }
+
+    /* Align the offset to the reference sample */
+    if ((ref_offset - offset) >= 0.0)
+      shift = (long)((ref_offset - offset) * rate + 0.5) / (double)rate;
+    else
+      shift = (long)((ref_offset - offset) * rate - 0.5) / (double)rate;
+
+    offset += shift;
+
+    if (fabs(ref_offset - offset) + ref_dispersion + dispersion >= 0.2 / rate) {
+      DEBUG_LOG("refclock pulse ignored offdiff=%.9f refdisp=%.9f disp=%.9f",
+          ref_offset - offset, ref_dispersion, dispersion);
+      return 0;
+    }
+
+    if (!check_pulse_edge(instance, ref_offset - offset, 0.0))
+      return 0;
+
+    leap = lock_refclock->leap_status;
+
+    DEBUG_LOG("refclock pulse offset=%.9f offdiff=%.9f samplediff=%.9f",
+              offset, ref_offset - offset, sample_diff);
+  } else {
+    struct timespec ref_time;
+    int is_synchronised, stratum;
+    double root_delay, root_dispersion, distance;
+    uint32_t ref_id;
+
+    /* Ignore the pulse if we are not well synchronized and the local
+       reference is not active */
+
+    REF_GetReferenceParams(cooked_time, &is_synchronised, &leap, &stratum,
+        &ref_id, &ref_time, &root_delay, &root_dispersion);
+    distance = fabs(root_delay) / 2 + root_dispersion;
+
+    if (leap == LEAP_Unsynchronised || distance >= 0.5 / rate) {
+      DEBUG_LOG("refclock pulse ignored offset=%.9f sync=%d dist=%.9f",
+                offset, leap != LEAP_Unsynchronised, distance);
+      /* Drop also all stored samples */
+      filter_reset(&instance->filter);
+      return 0;
+    }
+
+    if (!check_pulse_edge(instance, offset, distance))
+      return 0;
+  }
+
+  filter_add_sample(&instance->filter, cooked_time, offset, dispersion);
+  instance->leap_status = leap;
+  instance->pps_active = 1;
+
+  log_sample(instance, cooked_time, 0, 1, offset + raw_correction - instance->offset,
+             offset, dispersion);
+
+  /* for logging purposes */
+  if (!instance->driver->poll)
+    instance->driver_polled++;
+
+  return 1;
+}
+
+double
+RCL_GetPrecision(RCL_Instance instance)
+{
+  return instance->precision;
+}
+
+int
+RCL_GetDriverPoll(RCL_Instance instance)
+{
+  return instance->driver_poll;
+}
+
+static int
+valid_sample_time(RCL_Instance instance, struct timespec *sample_time)
+{
+  struct timespec now, last_sample_time;
+  double diff, last_offset, last_dispersion;
+
+  LCL_ReadCookedTime(&now, NULL);
+  diff = UTI_DiffTimespecsToDouble(&now, sample_time);
+
+  if (diff < 0.0 || diff > UTI_Log2ToDouble(instance->poll + 1) ||
+      (filter_get_samples(&instance->filter) > 0 &&
+       filter_get_last_sample(&instance->filter, &last_sample_time,
+                              &last_offset, &last_dispersion) &&
+       UTI_CompareTimespecs(&last_sample_time, sample_time) >= 0)) {
+    DEBUG_LOG("%s refclock sample time %s not valid age=%.6f",
+              UTI_RefidToString(instance->ref_id),
+              UTI_TimespecToString(sample_time), diff);
+    return 0;
+  }
+
+  return 1;
+}
+
+static int
+pps_stratum(RCL_Instance instance, struct timespec *ts)
+{
+  struct timespec ref_time;
+  int is_synchronised, stratum;
+  unsigned int i;
+  double root_delay, root_dispersion;
+  NTP_Leap leap;
+  uint32_t ref_id;
+  RCL_Instance refclock;
+
+  REF_GetReferenceParams(ts, &is_synchronised, &leap, &stratum,
+      &ref_id, &ref_time, &root_delay, &root_dispersion);
+
+  /* Don't change our stratum if the local reference is active
+     or this is the current source */
+  if (ref_id == instance->ref_id ||
+      (!is_synchronised && leap != LEAP_Unsynchronised))
+    return stratum - 1;
+
+  /* Or the current source is another PPS refclock */ 
+  for (i = 0; i < ARR_GetSize(refclocks); i++) {
+    refclock = get_refclock(i);
+    if (refclock->ref_id == ref_id &&
+        refclock->pps_active && refclock->lock_ref == -1)
+      return stratum - 1;
+  }
+
+  return 0;
+}
+
+static void
+poll_timeout(void *arg)
+{
+  int poll;
+
+  RCL_Instance inst = (RCL_Instance)arg;
+
+  poll = inst->poll;
+
+  if (inst->driver->poll) {
+    poll = inst->driver_poll;
+    inst->driver->poll(inst);
+    inst->driver_polled++;
+  }
+  
+  if (!(inst->driver->poll && inst->driver_polled < (1 << (inst->poll - inst->driver_poll)))) {
+    double offset, dispersion;
+    struct timespec sample_time;
+    int sample_ok, stratum;
+
+    sample_ok = filter_get_sample(&inst->filter, &sample_time, &offset, &dispersion);
+    inst->driver_polled = 0;
+
+    if (sample_ok) {
+      if (inst->pps_active && inst->lock_ref == -1)
+        /* Handle special case when PPS is used with local stratum */
+        stratum = pps_stratum(inst, &sample_time);
+      else
+        stratum = inst->stratum;
+
+      SRC_UpdateReachability(inst->source, 1);
+      SRC_AccumulateSample(inst->source, &sample_time, offset,
+          inst->delay, dispersion, inst->delay, dispersion, stratum, inst->leap_status);
+      SRC_SelectSource(inst->source);
+
+      log_sample(inst, &sample_time, 1, 0, 0.0, offset, dispersion);
+    } else {
+      SRC_UpdateReachability(inst->source, 0);
+    }
+  }
+
+  inst->timeout_id = SCH_AddTimeoutByDelay(UTI_Log2ToDouble(poll), poll_timeout, arg);
+}
+
+static void
+slew_samples(struct timespec *raw, struct timespec *cooked, double dfreq,
+             double doffset, LCL_ChangeType change_type, void *anything)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARR_GetSize(refclocks); i++) {
+    if (change_type == LCL_ChangeUnknownStep)
+      filter_reset(&get_refclock(i)->filter);
+    else
+      filter_slew_samples(&get_refclock(i)->filter, cooked, dfreq, doffset);
+  }
+}
+
+static void
+add_dispersion(double dispersion, void *anything)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARR_GetSize(refclocks); i++)
+    filter_add_dispersion(&get_refclock(i)->filter, dispersion);
+}
+
+static void
+log_sample(RCL_Instance instance, struct timespec *sample_time, int filtered, int pulse, double raw_offset, double cooked_offset, double dispersion)
+{
+  char sync_stats[4] = {'N', '+', '-', '?'};
+
+  if (logfileid == -1)
+    return;
+
+  if (!filtered) {
+    LOG_FileWrite(logfileid, "%s.%06d %-5s %3d %1c %1d %13.6e %13.6e %10.3e",
+      UTI_TimeToLogForm(sample_time->tv_sec),
+      (int)sample_time->tv_nsec / 1000,
+      UTI_RefidToString(instance->ref_id),
+      instance->driver_polled,
+      sync_stats[instance->leap_status],
+      pulse,
+      raw_offset,
+      cooked_offset,
+      dispersion);
+  } else {
+    LOG_FileWrite(logfileid, "%s.%06d %-5s   - %1c -       -       %13.6e %10.3e",
+      UTI_TimeToLogForm(sample_time->tv_sec),
+      (int)sample_time->tv_nsec / 1000,
+      UTI_RefidToString(instance->ref_id),
+      sync_stats[instance->leap_status],
+      cooked_offset,
+      dispersion);
+  }
+}
+
+static void
+filter_init(struct MedianFilter *filter, int length, double max_dispersion)
+{
+  if (length < 1)
+    length = 1;
+
+  filter->length = length;
+  filter->index = -1;
+  filter->used = 0;
+  filter->last = -1;
+  /* set first estimate to system precision */
+  filter->avg_var_n = 0;
+  filter->avg_var = LCL_GetSysPrecisionAsQuantum() * LCL_GetSysPrecisionAsQuantum();
+  filter->max_var = max_dispersion * max_dispersion;
+  filter->samples = MallocArray(struct FilterSample, filter->length);
+  filter->selected = MallocArray(int, filter->length);
+  filter->x_data = MallocArray(double, filter->length);
+  filter->y_data = MallocArray(double, filter->length);
+  filter->w_data = MallocArray(double, filter->length);
+}
+
+static void
+filter_fini(struct MedianFilter *filter)
+{
+  Free(filter->samples);
+  Free(filter->selected);
+  Free(filter->x_data);
+  Free(filter->y_data);
+  Free(filter->w_data);
+}
+
+static void
+filter_reset(struct MedianFilter *filter)
+{
+  filter->index = -1;
+  filter->used = 0;
+}
+
+static double
+filter_get_avg_sample_dispersion(struct MedianFilter *filter)
+{
+  return sqrt(filter->avg_var);
+}
+
+static void
+filter_add_sample(struct MedianFilter *filter, struct timespec *sample_time, double offset, double dispersion)
+{
+  filter->index++;
+  filter->index %= filter->length;
+  filter->last = filter->index;
+  if (filter->used < filter->length)
+    filter->used++;
+
+  filter->samples[filter->index].sample_time = *sample_time;
+  filter->samples[filter->index].offset = offset;
+  filter->samples[filter->index].dispersion = dispersion;
+
+  DEBUG_LOG("filter sample %d t=%s offset=%.9f dispersion=%.9f",
+      filter->index, UTI_TimespecToString(sample_time), offset, dispersion);
+}
+
+static int
+filter_get_last_sample(struct MedianFilter *filter, struct timespec *sample_time, double *offset, double *dispersion)
+{
+  if (filter->last < 0)
+    return 0;
+
+  *sample_time = filter->samples[filter->last].sample_time;
+  *offset = filter->samples[filter->last].offset;
+  *dispersion = filter->samples[filter->last].dispersion;
+  return 1;
+}
+
+static int
+filter_get_samples(struct MedianFilter *filter)
+{
+  return filter->used;
+}
+
+static const struct FilterSample *tmp_sorted_array;
+
+static int
+sample_compare(const void *a, const void *b)
+{
+  const struct FilterSample *s1, *s2;
+
+  s1 = &tmp_sorted_array[*(int *)a];
+  s2 = &tmp_sorted_array[*(int *)b];
+
+  if (s1->offset < s2->offset)
+    return -1;
+  else if (s1->offset > s2->offset)
+    return 1;
+  return 0;
+}
+
+int
+filter_select_samples(struct MedianFilter *filter)
+{
+  int i, j, k, o, from, to, *selected;
+  double min_dispersion;
+
+  if (filter->used < 1)
+    return 0;
+
+  /* for lengths below 4 require full filter,
+     for 4 and above require at least 4 samples */
+  if ((filter->length < 4 && filter->used != filter->length) ||
+      (filter->length >= 4 && filter->used < 4))
+    return 0;
+
+  selected = filter->selected;
+
+  if (filter->used > 4) {
+    /* select samples with dispersion better than 1.5 * minimum */
+
+    for (i = 1, min_dispersion = filter->samples[0].dispersion; i < filter->used; i++) {
+      if (min_dispersion > filter->samples[i].dispersion)
+        min_dispersion = filter->samples[i].dispersion;
+    }
+
+    for (i = j = 0; i < filter->used; i++) {
+      if (filter->samples[i].dispersion <= 1.5 * min_dispersion)
+        selected[j++] = i;
+    }
+  } else {
+    j = 0;
+  }
+
+  if (j < 4) {
+    /* select all samples */
+
+    for (j = 0; j < filter->used; j++)
+      selected[j] = j;
+  }
+
+  /* and sort their indices by offset */
+  tmp_sorted_array = filter->samples;
+  qsort(selected, j, sizeof (int), sample_compare);
+
+  /* select 60 percent of the samples closest to the median */ 
+  if (j > 2) {
+    from = j / 5;
+    if (from < 1)
+      from = 1;
+    to = j - from;
+  } else {
+    from = 0;
+    to = j;
+  }
+
+  /* mark unused samples and sort the rest from oldest to newest */
+
+  o = filter->used - filter->index - 1;
+
+  for (i = 0; i < from; i++)
+    selected[i] = -1;
+  for (; i < to; i++)
+    selected[i] = (selected[i] + o) % filter->used;
+  for (; i < filter->used; i++)
+    selected[i] = -1;
+
+  for (i = from; i < to; i++) {
+    j = selected[i];
+    selected[i] = -1;
+    while (j != -1 && selected[j] != j) {
+      k = selected[j];
+      selected[j] = j;
+      j = k;
+    }
+  }
+
+  for (i = j = 0, k = -1; i < filter->used; i++) {
+    if (selected[i] != -1)
+      selected[j++] = (selected[i] + filter->used - o) % filter->used;
+  }
+
+  return j;
+}
+
+static int
+filter_get_sample(struct MedianFilter *filter, struct timespec *sample_time, double *offset, double *dispersion)
+{
+  struct FilterSample *s, *ls;
+  int i, n, dof;
+  double x, y, d, e, var, prev_avg_var;
+
+  n = filter_select_samples(filter);
+
+  if (n < 1)
+    return 0;
+
+  ls = &filter->samples[filter->selected[n - 1]];
+
+  /* prepare data */
+  for (i = 0; i < n; i++) {
+    s = &filter->samples[filter->selected[i]];
+
+    filter->x_data[i] = UTI_DiffTimespecsToDouble(&s->sample_time, &ls->sample_time);
+    filter->y_data[i] = s->offset;
+    filter->w_data[i] = s->dispersion;
+  }
+
+  /* mean offset, sample time and sample dispersion */ 
+  for (i = 0, x = y = e = 0.0; i < n; i++) {
+    x += filter->x_data[i];
+    y += filter->y_data[i];
+    e += filter->w_data[i];
+  }
+  x /= n;
+  y /= n;
+  e /= n;
+
+  if (n >= 4) {
+    double b0, b1, s2, sb0, sb1;
+
+    /* set y axis to the mean sample time */
+    for (i = 0; i < n; i++)
+      filter->x_data[i] -= x;
+
+    /* make a linear fit and use the estimated standard deviation of intercept
+       as dispersion */
+    RGR_WeightedRegression(filter->x_data, filter->y_data, filter->w_data, n,
+        &b0, &b1, &s2, &sb0, &sb1);
+    var = s2;
+    d = sb0;
+    dof = n - 2;
+  } else if (n >= 2) {
+    for (i = 0, d = 0.0; i < n; i++)
+      d += (filter->y_data[i] - y) * (filter->y_data[i] - y);
+    var = d / (n - 1);
+    d = sqrt(var);
+    dof = n - 1;
+  } else {
+    var = filter->avg_var;
+    d = sqrt(var);
+    dof = 1;
+  }
+
+  /* avoid having zero dispersion */
+  if (var < 1e-20) {
+    var = 1e-20;
+    d = sqrt(var);
+  }
+
+  /* drop the sample if variance is larger than allowed maximum */
+  if (filter->max_var > 0.0 && var > filter->max_var) {
+    DEBUG_LOG("filter dispersion too large disp=%.9f max=%.9f",
+        sqrt(var), sqrt(filter->max_var));
+    return 0;
+  }
+
+  prev_avg_var = filter->avg_var;
+
+  /* update exponential moving average of the variance */
+  if (filter->avg_var_n > 50) {
+    filter->avg_var += dof / (dof + 50.0) * (var - filter->avg_var);
+  } else {
+    filter->avg_var = (filter->avg_var * filter->avg_var_n + var * dof) /
+      (dof + filter->avg_var_n);
+    if (filter->avg_var_n == 0)
+      prev_avg_var = filter->avg_var;
+    filter->avg_var_n += dof;
+  }
+
+  /* reduce noise in sourcestats weights by using the long-term average
+     instead of the estimated variance if it's not significantly lower */
+  if (var * dof / RGR_GetChi2Coef(dof) < prev_avg_var)
+    d = sqrt(filter->avg_var) * d / sqrt(var);
+
+  if (d < e)
+    d = e;
+
+  UTI_AddDoubleToTimespec(&ls->sample_time, x, sample_time);
+  *offset = y;
+  *dispersion = d;
+
+  filter_reset(filter);
+
+  return 1;
+}
+
+static void
+filter_slew_samples(struct MedianFilter *filter, struct timespec *when, double dfreq, double doffset)
+{
+  int i, first, last;
+  double delta_time;
+  struct timespec *sample;
+
+  if (filter->last < 0)
+    return;
+
+  /* always slew the last sample as it may be needed by PPS refclocks */
+  if (filter->used > 0) {
+    first = 0;
+    last = filter->used - 1;
+  } else {
+    first = last = filter->last;
+  }
+
+  for (i = first; i <= last; i++) {
+    sample = &filter->samples[i].sample_time;
+    UTI_AdjustTimespec(sample, when, sample, &delta_time, dfreq, doffset);
+    filter->samples[i].offset -= delta_time;
+  }
+}
+
+static void
+filter_add_dispersion(struct MedianFilter *filter, double dispersion)
+{
+  int i;
+
+  for (i = 0; i < filter->used; i++) {
+    filter->samples[i].dispersion += dispersion;
+  }
+}
diff --git a/chrony_3_3/refclock.h b/chrony_3_3/refclock.h
new file mode 100644
index 0000000..724f620
--- /dev/null
+++ b/chrony_3_3/refclock.h
@@ -0,0 +1,83 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2009
+ * 
+ * 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 refclocks.
+
+  */
+
+#ifndef GOT_REFCLOCK_H
+#define GOT_REFCLOCK_H
+
+#include "srcparams.h"
+#include "sources.h"
+
+typedef struct {
+  char *driver_name;
+  char *driver_parameter;
+  int driver_poll;
+  int poll;
+  int filter_length;
+  int pps_forced;
+  int pps_rate;
+  int min_samples;
+  int max_samples;
+  int sel_options;
+  int max_lock_age;
+  int stratum;
+  int tai;
+  uint32_t ref_id;
+  uint32_t lock_ref_id;
+  double offset;
+  double delay;
+  double precision;
+  double max_dispersion;
+  double pulse_width;
+} RefclockParameters;
+
+typedef struct RCL_Instance_Record *RCL_Instance;
+
+typedef struct {
+  int (*init)(RCL_Instance instance);
+  void (*fini)(RCL_Instance instance);
+  int (*poll)(RCL_Instance instance);
+} RefclockDriver;
+
+extern void RCL_Initialise(void);
+extern void RCL_Finalise(void);
+extern int RCL_AddRefclock(RefclockParameters *params);
+extern void RCL_StartRefclocks(void);
+extern void RCL_ReportSource(RPT_SourceReport *report, struct timespec *now);
+
+/* functions used by drivers */
+extern void RCL_SetDriverData(RCL_Instance instance, void *data);
+extern void *RCL_GetDriverData(RCL_Instance instance);
+extern char *RCL_GetDriverParameter(RCL_Instance instance);
+extern char *RCL_GetDriverOption(RCL_Instance instance, char *name);
+extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap);
+extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second);
+extern int RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
+                              double second, double dispersion, double raw_correction);
+extern double RCL_GetPrecision(RCL_Instance instance);
+extern int RCL_GetDriverPoll(RCL_Instance instance);
+
+#endif
diff --git a/chrony_3_3/refclock_phc.c b/chrony_3_3/refclock_phc.c
new file mode 100644
index 0000000..6aa5edd
--- /dev/null
+++ b/chrony_3_3/refclock_phc.c
@@ -0,0 +1,176 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2013, 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  PTP hardware clock (PHC) refclock driver.
+
+  */
+
+#include "config.h"
+
+#include "refclock.h"
+
+#ifdef FEAT_PHC
+
+#include "sysincl.h"
+
+#include "refclock.h"
+#include "hwclock.h"
+#include "local.h"
+#include "logging.h"
+#include "memory.h"
+#include "util.h"
+#include "sched.h"
+#include "sys_linux.h"
+
+struct phc_instance {
+  int fd;
+  int mode;
+  int nocrossts;
+  int extpps;
+  int pin;
+  int channel;
+  HCL_Instance clock;
+};
+
+static void read_ext_pulse(int sockfd, int event, void *anything);
+
+static int phc_initialise(RCL_Instance instance)
+{
+  struct phc_instance *phc;
+  int phc_fd, rising_edge;
+  char *path, *s;
+
+  path = RCL_GetDriverParameter(instance);
+ 
+  phc_fd = SYS_Linux_OpenPHC(path, 0);
+  if (phc_fd < 0) {
+    LOG_FATAL("Could not open PHC");
+    return 0;
+  }
+
+  phc = MallocNew(struct phc_instance);
+  phc->fd = phc_fd;
+  phc->mode = 0;
+  phc->nocrossts = RCL_GetDriverOption(instance, "nocrossts") ? 1 : 0;
+  phc->extpps = RCL_GetDriverOption(instance, "extpps") ? 1 : 0;
+
+  if (phc->extpps) {
+    s = RCL_GetDriverOption(instance, "pin");
+    phc->pin = s ? atoi(s) : 0;
+    s = RCL_GetDriverOption(instance, "channel");
+    phc->channel = s ? atoi(s) : 0;
+    rising_edge = RCL_GetDriverOption(instance, "clear") ? 0 : 1;
+    phc->clock = HCL_CreateInstance(UTI_Log2ToDouble(RCL_GetDriverPoll(instance)));
+
+    if (!SYS_Linux_SetPHCExtTimestamping(phc->fd, phc->pin, phc->channel,
+                                         rising_edge, !rising_edge, 1))
+      LOG_FATAL("Could not enable external PHC timestamping");
+
+    SCH_AddFileHandler(phc->fd, SCH_FILE_INPUT, read_ext_pulse, instance);
+  } else {
+    phc->pin = phc->channel = 0;
+    phc->clock = NULL;
+  }
+
+  RCL_SetDriverData(instance, phc);
+  return 1;
+}
+
+static void phc_finalise(RCL_Instance instance)
+{
+  struct phc_instance *phc;
+
+  phc = (struct phc_instance *)RCL_GetDriverData(instance);
+
+  if (phc->extpps) {
+    SCH_RemoveFileHandler(phc->fd);
+    SYS_Linux_SetPHCExtTimestamping(phc->fd, phc->pin, phc->channel, 0, 0, 0);
+    HCL_DestroyInstance(phc->clock);
+  }
+
+  close(phc->fd);
+  Free(phc);
+}
+
+static void read_ext_pulse(int fd, int event, void *anything)
+{
+  RCL_Instance instance;
+  struct phc_instance *phc;
+  struct timespec phc_ts, local_ts;
+  double local_err;
+  int channel;
+
+  instance = anything;
+  phc = RCL_GetDriverData(instance);
+
+  if (!SYS_Linux_ReadPHCExtTimestamp(phc->fd, &phc_ts, &channel))
+    return;
+
+  if (channel != phc->channel) {
+    DEBUG_LOG("Unexpected extts channel %d\n", channel);
+    return;
+  }
+
+  if (!HCL_CookTime(phc->clock, &phc_ts, &local_ts, &local_err))
+    return;
+
+  RCL_AddCookedPulse(instance, &local_ts, 1.0e-9 * local_ts.tv_nsec, local_err,
+                     UTI_DiffTimespecsToDouble(&phc_ts, &local_ts));
+}
+
+static int phc_poll(RCL_Instance instance)
+{
+  struct phc_instance *phc;
+  struct timespec phc_ts, sys_ts, local_ts;
+  double offset, phc_err, local_err;
+
+  phc = (struct phc_instance *)RCL_GetDriverData(instance);
+
+  if (!SYS_Linux_GetPHCSample(phc->fd, phc->nocrossts, RCL_GetPrecision(instance),
+                              &phc->mode, &phc_ts, &sys_ts, &phc_err))
+    return 0;
+
+  if (phc->extpps) {
+    LCL_CookTime(&sys_ts, &local_ts, &local_err);
+    HCL_AccumulateSample(phc->clock, &phc_ts, &local_ts, phc_err + local_err);
+    return 0;
+  }
+
+  offset = UTI_DiffTimespecsToDouble(&phc_ts, &sys_ts);
+
+  DEBUG_LOG("PHC offset: %+.9f err: %.9f", offset, phc_err);
+
+  return RCL_AddSample(instance, &sys_ts, offset, LEAP_Normal);
+}
+
+RefclockDriver RCL_PHC_driver = {
+  phc_initialise,
+  phc_finalise,
+  phc_poll
+};
+
+#else
+
+RefclockDriver RCL_PHC_driver = { NULL, NULL, NULL };
+
+#endif
diff --git a/chrony_3_3/refclock_pps.c b/chrony_3_3/refclock_pps.c
new file mode 100644
index 0000000..6f0565e
--- /dev/null
+++ b/chrony_3_3/refclock_pps.c
@@ -0,0 +1,169 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2009
+ * 
+ * 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  PPSAPI refclock driver.
+
+  */
+
+#include "config.h"
+
+#include "refclock.h"
+
+#if FEAT_PPS
+
+#if defined(HAVE_SYS_TIMEPPS_H)
+#include <sys/timepps.h>
+#elif defined(HAVE_TIMEPPS_H)
+#include <timepps.h>
+#endif
+
+#include "logging.h"
+#include "memory.h"
+#include "util.h"
+
+struct pps_instance {
+  pps_handle_t handle;
+  pps_seq_t last_seq;
+  int edge_clear;
+};
+
+static int pps_initialise(RCL_Instance instance) {
+  pps_handle_t handle;
+  pps_params_t params;
+  struct pps_instance *pps;
+  int fd, edge_clear, mode;
+  char *path;
+
+  path = RCL_GetDriverParameter(instance);
+  edge_clear = RCL_GetDriverOption(instance, "clear") ? 1 : 0;
+
+  fd = open(path, O_RDWR);
+  if (fd < 0) {
+    LOG_FATAL("open() failed on %s", path);
+    return 0;
+  }
+
+  UTI_FdSetCloexec(fd);
+
+  if (time_pps_create(fd, &handle) < 0) {
+    LOG_FATAL("time_pps_create() failed on %s", path);
+    return 0;
+  }
+
+  if (time_pps_getcap(handle, &mode) < 0) {
+    LOG_FATAL("time_pps_getcap() failed on %s", path);
+    return 0;
+  }
+
+  if (time_pps_getparams(handle, &params) < 0) {
+    LOG_FATAL("time_pps_getparams() failed on %s", path);
+    return 0;
+  }
+
+  if (!edge_clear) {
+    if (!(mode & PPS_CAPTUREASSERT)) {
+      LOG_FATAL("CAPTUREASSERT not supported on %s", path);
+      return 0;
+    }
+    params.mode |= PPS_CAPTUREASSERT;
+    params.mode &= ~PPS_CAPTURECLEAR;
+  } else {
+    if (!(mode & PPS_CAPTURECLEAR)) {
+      LOG_FATAL("CAPTURECLEAR not supported on %s", path);
+      return 0;
+    }
+    params.mode |= PPS_CAPTURECLEAR;
+    params.mode &= ~PPS_CAPTUREASSERT;
+  }
+
+  if (time_pps_setparams(handle, &params) < 0) {
+    LOG_FATAL("time_pps_setparams() failed on %s", path);
+    return 0;
+  }
+
+
+  pps = MallocNew(struct pps_instance);
+  pps->handle = handle;
+  pps->last_seq = 0;
+  pps->edge_clear = edge_clear;
+
+  RCL_SetDriverData(instance, pps);
+  return 1;
+}
+
+static void pps_finalise(RCL_Instance instance)
+{
+  struct pps_instance *pps; 
+
+  pps = (struct pps_instance *)RCL_GetDriverData(instance);
+  time_pps_destroy(pps->handle);
+  Free(pps);
+}
+
+static int pps_poll(RCL_Instance instance)
+{
+  struct pps_instance *pps; 
+  struct timespec ts;
+  pps_info_t pps_info;
+  pps_seq_t seq;
+
+  pps = (struct pps_instance *)RCL_GetDriverData(instance);
+
+  ts.tv_sec = 0;
+  ts.tv_nsec = 0;
+
+  if (time_pps_fetch(pps->handle, PPS_TSFMT_TSPEC, &pps_info, &ts) < 0) {
+    LOG(LOGS_ERR, "time_pps_fetch() failed : %s", strerror(errno));
+    return 0;
+  }
+
+  if (!pps->edge_clear) {
+    seq = pps_info.assert_sequence;
+    ts = pps_info.assert_timestamp;
+  } else {
+    seq = pps_info.clear_sequence;
+    ts = pps_info.clear_timestamp;
+  }
+
+  if (seq == pps->last_seq || UTI_IsZeroTimespec(&ts)) {
+    DEBUG_LOG("PPS sample ignored seq=%lu ts=%s",
+              seq, UTI_TimespecToString(&ts));
+    return 0;
+  }
+
+  pps->last_seq = seq;
+
+  return RCL_AddPulse(instance, &ts, 1.0e-9 * ts.tv_nsec);
+}
+
+RefclockDriver RCL_PPS_driver = {
+  pps_initialise,
+  pps_finalise,
+  pps_poll
+};
+
+#else
+
+RefclockDriver RCL_PPS_driver = { NULL, NULL, NULL };
+
+#endif
diff --git a/chrony_3_3/refclock_shm.c b/chrony_3_3/refclock_shm.c
new file mode 100644
index 0000000..7cced1d
--- /dev/null
+++ b/chrony_3_3/refclock_shm.c
@@ -0,0 +1,133 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2009
+ * 
+ * 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  SHM refclock driver.
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "refclock.h"
+#include "logging.h"
+#include "util.h"
+
+#define SHMKEY 0x4e545030
+
+struct shmTime {
+  int    mode; /* 0 - if valid set
+                *       use values, 
+                *       clear valid
+                * 1 - if valid set 
+                *       if count before and after read of values is equal,
+                *         use values 
+                *       clear valid
+                */
+  volatile int count;
+  time_t clockTimeStampSec;
+  int    clockTimeStampUSec;
+  time_t receiveTimeStampSec;
+  int    receiveTimeStampUSec;
+  int    leap;
+  int    precision;
+  int    nsamples;
+  volatile int valid;
+  int    clockTimeStampNSec;
+  int    receiveTimeStampNSec;
+  int    dummy[8]; 
+};
+
+static int shm_initialise(RCL_Instance instance) {
+  int id, param, perm;
+  char *s;
+  struct shmTime *shm;
+
+  param = atoi(RCL_GetDriverParameter(instance));
+  s = RCL_GetDriverOption(instance, "perm");
+  perm = s ? strtol(s, NULL, 8) & 0777 : 0600;
+
+  id = shmget(SHMKEY + param, sizeof (struct shmTime), IPC_CREAT | perm);
+  if (id == -1) {
+    LOG_FATAL("shmget() failed");
+    return 0;
+  }
+   
+  shm = (struct shmTime *)shmat(id, 0, 0);
+  if ((long)shm == -1) {
+    LOG_FATAL("shmat() failed");
+    return 0;
+  }
+
+  RCL_SetDriverData(instance, shm);
+  return 1;
+}
+
+static void shm_finalise(RCL_Instance instance)
+{
+  shmdt(RCL_GetDriverData(instance));
+}
+
+static int shm_poll(RCL_Instance instance)
+{
+  struct timespec receive_ts, clock_ts;
+  struct shmTime t, *shm;
+  double offset;
+
+  shm = (struct shmTime *)RCL_GetDriverData(instance);
+
+  t = *shm;
+  
+  if ((t.mode == 1 && t.count != shm->count) ||
+    !(t.mode == 0 || t.mode == 1) || !t.valid) {
+    DEBUG_LOG("SHM sample ignored mode=%d count=%d valid=%d",
+        t.mode, t.count, t.valid);
+    return 0;
+  }
+
+  shm->valid = 0;
+
+  receive_ts.tv_sec = t.receiveTimeStampSec;
+  clock_ts.tv_sec = t.clockTimeStampSec;
+
+  if (t.clockTimeStampNSec / 1000 == t.clockTimeStampUSec &&
+      t.receiveTimeStampNSec / 1000 == t.receiveTimeStampUSec) {
+    receive_ts.tv_nsec = t.receiveTimeStampNSec;
+    clock_ts.tv_nsec = t.clockTimeStampNSec;
+  } else {
+    receive_ts.tv_nsec = 1000 * t.receiveTimeStampUSec;
+    clock_ts.tv_nsec = 1000 * t.clockTimeStampUSec;
+  }
+
+  UTI_NormaliseTimespec(&clock_ts);
+  UTI_NormaliseTimespec(&receive_ts);
+  offset = UTI_DiffTimespecsToDouble(&clock_ts, &receive_ts);
+
+  return RCL_AddSample(instance, &receive_ts, offset, t.leap);
+}
+
+RefclockDriver RCL_SHM_driver = {
+  shm_initialise,
+  shm_finalise,
+  shm_poll
+};
diff --git a/chrony_3_3/refclock_sock.c b/chrony_3_3/refclock_sock.c
new file mode 100644
index 0000000..eb96147
--- /dev/null
+++ b/chrony_3_3/refclock_sock.c
@@ -0,0 +1,145 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2009
+ * 
+ * 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Unix domain socket refclock driver.
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "refclock.h"
+#include "logging.h"
+#include "util.h"
+#include "sched.h"
+
+#define SOCK_MAGIC 0x534f434b
+
+struct sock_sample {
+  /* Time of the measurement (system time) */
+  struct timeval tv;
+
+  /* Offset between the true time and the system time (in seconds) */
+  double offset;
+
+  /* Non-zero if the sample is from a PPS signal, i.e. another source
+     is needed to obtain seconds */
+  int pulse;
+
+  /* 0 - normal, 1 - insert leap second, 2 - delete leap second */
+  int leap;
+
+  /* Padding, ignored */
+  int _pad;
+
+  /* Protocol identifier (0x534f434b) */
+  int magic;
+};
+
+static void read_sample(int sockfd, int event, void *anything)
+{
+  struct sock_sample sample;
+  struct timespec ts;
+  RCL_Instance instance;
+  int s;
+
+  instance = (RCL_Instance)anything;
+
+  s = recv(sockfd, &sample, sizeof (sample), 0);
+
+  if (s < 0) {
+    LOG(LOGS_ERR, "Could not read SOCK sample : %s",
+        strerror(errno));
+    return;
+  }
+
+  if (s != sizeof (sample)) {
+    LOG(LOGS_WARN, "Unexpected length of SOCK sample : %d != %ld",
+        s, (long)sizeof (sample));
+    return;
+  }
+
+  if (sample.magic != SOCK_MAGIC) {
+    LOG(LOGS_WARN, "Unexpected magic number in SOCK sample : %x != %x",
+        sample.magic, SOCK_MAGIC);
+    return;
+  }
+
+  UTI_TimevalToTimespec(&sample.tv, &ts);
+  UTI_NormaliseTimespec(&ts);
+
+  if (sample.pulse) {
+    RCL_AddPulse(instance, &ts, sample.offset);
+  } else {
+    RCL_AddSample(instance, &ts, sample.offset, sample.leap);
+  }
+}
+
+static int sock_initialise(RCL_Instance instance)
+{
+  struct sockaddr_un s;
+  int sockfd;
+  char *path;
+
+  path = RCL_GetDriverParameter(instance);
+ 
+  s.sun_family = AF_UNIX;
+  if (snprintf(s.sun_path, sizeof (s.sun_path), "%s", path) >= sizeof (s.sun_path)) {
+    LOG_FATAL("path %s is too long", path);
+    return 0;
+  }
+
+  sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
+  if (sockfd < 0) {
+    LOG_FATAL("socket() failed");
+    return 0;
+  }
+
+  UTI_FdSetCloexec(sockfd);
+
+  unlink(path);
+  if (bind(sockfd, (struct sockaddr *)&s, sizeof (s)) < 0) {
+    LOG_FATAL("bind() failed");
+    return 0;
+  }
+
+  RCL_SetDriverData(instance, (void *)(long)sockfd);
+  SCH_AddFileHandler(sockfd, SCH_FILE_INPUT, read_sample, instance);
+  return 1;
+}
+
+static void sock_finalise(RCL_Instance instance)
+{
+  int sockfd;
+
+  sockfd = (long)RCL_GetDriverData(instance);
+  SCH_RemoveFileHandler(sockfd);
+  close(sockfd);
+}
+
+RefclockDriver RCL_SOCK_driver = {
+  sock_initialise,
+  sock_finalise,
+  NULL
+};
diff --git a/chrony_3_3/reference.c b/chrony_3_3/reference.c
new file mode 100644
index 0000000..dff7ab9
--- /dev/null
+++ b/chrony_3_3/reference.c
@@ -0,0 +1,1404 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  This module keeps track of the source which we are claiming to be
+  our reference, for the purposes of generating outgoing NTP packets */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "memory.h"
+#include "reference.h"
+#include "util.h"
+#include "conf.h"
+#include "logging.h"
+#include "local.h"
+#include "sched.h"
+
+/* ================================================== */
+
+/* The minimum allowed skew */
+#define MIN_SKEW 1.0e-12
+
+static int are_we_synchronised;
+static int enable_local_stratum;
+static int local_stratum;
+static int local_orphan;
+static double local_distance;
+static NTP_Leap our_leap_status;
+static int our_leap_sec;
+static int our_tai_offset;
+static int our_stratum;
+static uint32_t our_ref_id;
+static IPAddr our_ref_ip;
+static struct timespec our_ref_time;
+static double our_skew;
+static double our_residual_freq;
+static double our_root_delay;
+static double our_root_dispersion;
+
+static double max_update_skew;
+
+static double last_offset;
+static double avg2_offset;
+static int avg2_moving;
+
+static double correction_time_ratio;
+
+/* Flag indicating that we are initialised */
+static int initialised = 0;
+
+/* Current operating mode */
+static REF_Mode mode;
+
+/* Threshold and update limit for stepping clock */
+static int make_step_limit;
+static double make_step_threshold;
+
+/* Number of updates before offset checking, number of ignored updates
+   before exiting and the maximum allowed offset */
+static int max_offset_delay;
+static int max_offset_ignore;
+static double max_offset;
+
+/* Threshold for logging clock changes to syslog */
+static double log_change_threshold;
+
+/* Flag, threshold and user for sending mail notification on large clock changes */
+static int do_mail_change;
+static double mail_change_threshold;
+static char *mail_change_user;
+
+/* Handler for mode ending */
+static REF_ModeEndHandler mode_end_handler = NULL;
+
+/* Filename of the drift file. */
+static char *drift_file=NULL;
+static double drift_file_age;
+
+static void update_drift_file(double, double);
+
+/* Leap second handling mode */
+static REF_LeapMode leap_mode;
+
+/* Flag indicating the clock was recently corrected for leap second and it may
+   not have correct time yet (missing 23:59:60 in the UTC time scale) */
+static int leap_in_progress;
+
+/* Timer for the leap second handler */
+static SCH_TimeoutID leap_timeout_id;
+
+/* Name of a system timezone containing leap seconds occuring at midnight */
+static char *leap_tzname;
+
+/* ================================================== */
+
+static LOG_FileID logfileid;
+
+/* ================================================== */
+
+/* Exponential moving averages of absolute clock frequencies
+   used as a fallback when synchronisation is lost. */
+
+struct fb_drift {
+  double freq;
+  double secs;
+};
+
+static int fb_drift_min;
+static int fb_drift_max;
+
+static struct fb_drift *fb_drifts = NULL;
+static int next_fb_drift;
+static SCH_TimeoutID fb_drift_timeout_id;
+
+/* Timestamp of last reference update */
+static struct timespec last_ref_update;
+static double last_ref_update_interval;
+
+/* ================================================== */
+
+static NTP_Leap get_tz_leap(time_t when, int *tai_offset);
+static void update_leap_status(NTP_Leap leap, time_t now, int reset);
+
+/* ================================================== */
+
+static void
+handle_slew(struct timespec *raw,
+            struct timespec *cooked,
+            double dfreq,
+            double doffset,
+            LCL_ChangeType change_type,
+            void *anything)
+{
+  double delta;
+  struct timespec now;
+
+  if (!UTI_IsZeroTimespec(&our_ref_time))
+    UTI_AdjustTimespec(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
+
+  if (change_type == LCL_ChangeUnknownStep) {
+    UTI_ZeroTimespec(&last_ref_update);
+  } else if (last_ref_update.tv_sec) {
+    UTI_AdjustTimespec(&last_ref_update, cooked, &last_ref_update, &delta, dfreq, doffset);
+  }
+
+  /* When the clock was stepped, check if that doesn't change our leap status
+     and also reset the leap timeout to undo the shift in the scheduler */
+  if (change_type != LCL_ChangeAdjust && our_leap_sec && !leap_in_progress) {
+    LCL_ReadRawTime(&now);
+    update_leap_status(our_leap_status, now.tv_sec, 1);
+  }
+}
+
+/* ================================================== */
+
+void
+REF_Initialise(void)
+{
+  FILE *in;
+  double file_freq_ppm, file_skew_ppm;
+  double our_frequency_ppm;
+  int tai_offset;
+
+  mode = REF_ModeNormal;
+  are_we_synchronised = 0;
+  our_leap_status = LEAP_Unsynchronised;
+  our_leap_sec = 0;
+  our_tai_offset = 0;
+  initialised = 1;
+  our_root_dispersion = 1.0;
+  our_root_delay = 1.0;
+  our_frequency_ppm = 0.0;
+  our_skew = 1.0; /* i.e. rather bad */
+  our_residual_freq = 0.0;
+  drift_file_age = 0.0;
+
+  /* Now see if we can get the drift file opened */
+  drift_file = CNF_GetDriftFile();
+  if (drift_file) {
+    in = fopen(drift_file, "r");
+    if (in) {
+      if (fscanf(in, "%lf%lf", &file_freq_ppm, &file_skew_ppm) == 2) {
+        /* We have read valid data */
+        our_frequency_ppm = file_freq_ppm;
+        our_skew = 1.0e-6 * file_skew_ppm;
+        if (our_skew < MIN_SKEW)
+          our_skew = MIN_SKEW;
+        LOG(LOGS_INFO, "Frequency %.3f +/- %.3f ppm read from %s",
+            file_freq_ppm, file_skew_ppm, drift_file);
+        LCL_SetAbsoluteFrequency(our_frequency_ppm);
+      } else {
+        LOG(LOGS_WARN, "Could not read valid frequency and skew from driftfile %s",
+            drift_file);
+      }
+      fclose(in);
+    }
+  }
+    
+  if (our_frequency_ppm == 0.0) {
+    our_frequency_ppm = LCL_ReadAbsoluteFrequency();
+    if (our_frequency_ppm != 0.0) {
+      LOG(LOGS_INFO, "Initial frequency %.3f ppm", our_frequency_ppm);
+    }
+  }
+
+  logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking",
+      "   Date (UTC) Time     IP Address   St   Freq ppm   Skew ppm     Offset L Co  Offset sd Rem. corr. Root delay Root disp. Max. error")
+    : -1;
+
+  max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
+
+  correction_time_ratio = CNF_GetCorrectionTimeRatio();
+
+  enable_local_stratum = CNF_AllowLocalReference(&local_stratum, &local_orphan, &local_distance);
+
+  leap_timeout_id = 0;
+  leap_in_progress = 0;
+  leap_mode = CNF_GetLeapSecMode();
+  /* Switch to step mode if the system driver doesn't support leap */
+  if (leap_mode == REF_LeapModeSystem && !LCL_CanSystemLeap())
+    leap_mode = REF_LeapModeStep;
+
+  leap_tzname = CNF_GetLeapSecTimezone();
+  if (leap_tzname) {
+    /* Check that the timezone has good data for Jun 30 2012 and Dec 31 2012 */
+    if (get_tz_leap(1341014400, &tai_offset) == LEAP_InsertSecond && tai_offset == 34 &&
+        get_tz_leap(1356912000, &tai_offset) == LEAP_Normal && tai_offset == 35) {
+      LOG(LOGS_INFO, "Using %s timezone to obtain leap second data", leap_tzname);
+    } else {
+      LOG(LOGS_WARN, "Timezone %s failed leap second check, ignoring", leap_tzname);
+      leap_tzname = NULL;
+    }
+  }
+
+  CNF_GetMakeStep(&make_step_limit, &make_step_threshold);
+  CNF_GetMaxChange(&max_offset_delay, &max_offset_ignore, &max_offset);
+  CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user);
+  log_change_threshold = CNF_GetLogChange();
+
+  CNF_GetFallbackDrifts(&fb_drift_min, &fb_drift_max);
+
+  if (fb_drift_max >= fb_drift_min && fb_drift_min > 0) {
+    fb_drifts = MallocArray(struct fb_drift, fb_drift_max - fb_drift_min + 1);
+    memset(fb_drifts, 0, sizeof (struct fb_drift) * (fb_drift_max - fb_drift_min + 1));
+    next_fb_drift = 0;
+    fb_drift_timeout_id = 0;
+  }
+
+  UTI_ZeroTimespec(&our_ref_time);
+  UTI_ZeroTimespec(&last_ref_update);
+  last_ref_update_interval = 0.0;
+
+  LCL_AddParameterChangeHandler(handle_slew, NULL);
+
+  /* Make first entry in tracking log */
+  REF_SetUnsynchronised();
+}
+
+/* ================================================== */
+
+void
+REF_Finalise(void)
+{
+  update_leap_status(LEAP_Unsynchronised, 0, 0);
+
+  if (drift_file) {
+    update_drift_file(LCL_ReadAbsoluteFrequency(), our_skew);
+  }
+
+  Free(fb_drifts);
+
+  initialised = 0;
+}
+
+/* ================================================== */
+
+void REF_SetMode(REF_Mode new_mode)
+{
+  mode = new_mode;
+}
+
+/* ================================================== */
+
+REF_Mode
+REF_GetMode(void)
+{
+  return mode;
+}
+
+/* ================================================== */
+
+void
+REF_SetModeEndHandler(REF_ModeEndHandler handler)
+{
+  mode_end_handler = handler;
+}
+
+/* ================================================== */
+
+REF_LeapMode
+REF_GetLeapMode(void)
+{
+  return leap_mode;
+}
+
+/* ================================================== */
+
+static double
+Sqr(double x)
+{
+  return x*x;
+}
+
+/* ================================================== */
+#if 0
+static double
+Cube(double x)
+{
+  return x*x*x;
+}
+#endif
+
+/* ================================================== */
+/* Update the drift coefficients to the file. */
+
+static void
+update_drift_file(double freq_ppm, double skew)
+{
+  struct stat buf;
+  char *temp_drift_file;
+  FILE *out;
+  int r1, r2;
+
+  /* Create a temporary file with a '.tmp' extension. */
+
+  temp_drift_file = (char*) Malloc(strlen(drift_file)+8);
+
+  if(!temp_drift_file) {
+    return;
+  }
+
+  strcpy(temp_drift_file,drift_file);
+  strcat(temp_drift_file,".tmp");
+
+  out = fopen(temp_drift_file, "w");
+  if (!out) {
+    Free(temp_drift_file);
+    LOG(LOGS_WARN, "Could not open temporary driftfile %s.tmp for writing",
+        drift_file);
+    return;
+  }
+
+  /* Write the frequency and skew parameters in ppm */
+  r1 = fprintf(out, "%20.6f %20.6f\n", freq_ppm, 1.0e6 * skew);
+  r2 = fclose(out);
+  if (r1 < 0 || r2) {
+    Free(temp_drift_file);
+    LOG(LOGS_WARN, "Could not write to temporary driftfile %s.tmp",
+        drift_file);
+    return;
+  }
+
+  /* Clone the file attributes from the existing file if there is one. */
+
+  if (!stat(drift_file,&buf)) {
+    if (chown(temp_drift_file,buf.st_uid,buf.st_gid) ||
+        chmod(temp_drift_file,buf.st_mode & 0777)) {
+      LOG(LOGS_WARN, "Could not change ownership or permissions of temporary driftfile %s.tmp",
+          drift_file);
+    }
+  }
+
+  /* Rename the temporary file to the correct location (see rename(2) for details). */
+
+  if (rename(temp_drift_file,drift_file)) {
+    unlink(temp_drift_file);
+    Free(temp_drift_file);
+    LOG(LOGS_WARN, "Could not replace old driftfile %s with new one %s.tmp",
+        drift_file,drift_file);
+    return;
+  }
+
+  Free(temp_drift_file);
+}
+
+/* ================================================== */
+
+static void
+update_fb_drifts(double freq_ppm, double update_interval)
+{
+  int i, secs;
+
+  assert(are_we_synchronised);
+
+  if (next_fb_drift > 0) {
+#if 0
+    /* Reset drifts that were used when we were unsynchronised */
+    for (i = 0; i < next_fb_drift - fb_drift_min; i++)
+      fb_drifts[i].secs = 0.0;
+#endif
+    next_fb_drift = 0;
+  }
+
+  SCH_RemoveTimeout(fb_drift_timeout_id);
+  fb_drift_timeout_id = 0;
+
+  if (update_interval < 1.0 || update_interval > last_ref_update_interval * 4.0)
+    return;
+
+  for (i = 0; i < fb_drift_max - fb_drift_min + 1; i++) {
+    secs = 1 << (i + fb_drift_min);
+    if (fb_drifts[i].secs < secs) {
+      /* Calculate average over 2 * secs interval before switching to
+         exponential updating */
+      fb_drifts[i].freq = (fb_drifts[i].freq * fb_drifts[i].secs +
+          update_interval * 0.5 * freq_ppm) / (update_interval * 0.5 + fb_drifts[i].secs);
+      fb_drifts[i].secs += update_interval * 0.5;
+    } else {
+      /* Update exponential moving average. The smoothing factor for update
+         interval equal to secs is about 0.63, for half interval about 0.39,
+         for double interval about 0.86. */
+      fb_drifts[i].freq += (1 - 1.0 / exp(update_interval / secs)) *
+        (freq_ppm - fb_drifts[i].freq);
+    }
+
+    DEBUG_LOG("Fallback drift %d updated: %f ppm %f seconds",
+              i + fb_drift_min, fb_drifts[i].freq, fb_drifts[i].secs);
+  }
+}
+
+/* ================================================== */
+
+static void
+fb_drift_timeout(void *arg)
+{
+  assert(next_fb_drift >= fb_drift_min && next_fb_drift <= fb_drift_max);
+
+  fb_drift_timeout_id = 0;
+
+  DEBUG_LOG("Fallback drift %d active: %f ppm",
+            next_fb_drift, fb_drifts[next_fb_drift - fb_drift_min].freq);
+  LCL_SetAbsoluteFrequency(fb_drifts[next_fb_drift - fb_drift_min].freq);
+  REF_SetUnsynchronised();
+}
+
+/* ================================================== */
+
+static void
+schedule_fb_drift(struct timespec *now)
+{
+  int i, c, secs;
+  double unsynchronised;
+  struct timespec when;
+
+  if (fb_drift_timeout_id)
+    return; /* already scheduled */
+
+  unsynchronised = UTI_DiffTimespecsToDouble(now, &last_ref_update);
+
+  for (c = secs = 0, i = fb_drift_min; i <= fb_drift_max; i++) {
+    secs = 1 << i;
+
+    if (fb_drifts[i - fb_drift_min].secs < secs)
+      continue;
+
+    if (unsynchronised < secs && i > next_fb_drift)
+      break;
+
+    c = i;
+  }
+
+  if (c > next_fb_drift) {
+    LCL_SetAbsoluteFrequency(fb_drifts[c - fb_drift_min].freq);
+    next_fb_drift = c;
+    DEBUG_LOG("Fallback drift %d set", c);
+  }
+
+  if (i <= fb_drift_max) {
+    next_fb_drift = i;
+    UTI_AddDoubleToTimespec(now, secs - unsynchronised, &when);
+    fb_drift_timeout_id = SCH_AddTimeout(&when, fb_drift_timeout, NULL);
+    DEBUG_LOG("Fallback drift %d scheduled", i);
+  }
+}
+
+/* ================================================== */
+
+static void
+end_ref_mode(int result)
+{
+  mode = REF_ModeIgnore;
+
+  /* Dispatch the handler */
+  if (mode_end_handler)
+    (mode_end_handler)(result);
+}
+
+/* ================================================== */
+
+#define BUFLEN 255
+#define S_MAX_USER_LEN "128"
+
+static void
+maybe_log_offset(double offset, time_t now)
+{
+  double abs_offset;
+  FILE *p;
+  char buffer[BUFLEN], host[BUFLEN];
+  struct tm stm;
+
+  abs_offset = fabs(offset);
+
+  if (abs_offset > log_change_threshold) {
+    LOG(LOGS_WARN, "System clock wrong by %.6f seconds, adjustment started",
+        -offset);
+  }
+
+  if (do_mail_change &&
+      (abs_offset > mail_change_threshold)) {
+    snprintf(buffer, sizeof(buffer), "%s %." S_MAX_USER_LEN "s", MAIL_PROGRAM, mail_change_user);
+    p = popen(buffer, "w");
+    if (p) {
+      if (gethostname(host, sizeof(host)) < 0) {
+        strcpy(host, "<UNKNOWN>");
+      }
+      fprintf(p, "Subject: chronyd reports change to system clock on node [%s]\n", host);
+      fputs("\n", p);
+      stm = *localtime(&now);
+      strftime(buffer, sizeof(buffer), "On %A, %d %B %Y\n  with the system clock reading %H:%M:%S (%Z)", &stm);
+      fputs(buffer, p);
+      /* If offset < 0 the local clock is slow, so we are applying a
+         positive change to it to bring it into line, hence the
+         negation of 'offset' in the next statement (and earlier) */
+      fprintf(p,
+              "\n\nchronyd started to apply an adjustment of %.3f seconds to it,\n"
+              "  which exceeded the reporting threshold of %.3f seconds\n\n",
+              -offset, mail_change_threshold);
+      pclose(p);
+    } else {
+      LOG(LOGS_ERR, "Could not send mail notification to user %s\n",
+          mail_change_user);
+    }
+  }
+
+}
+
+/* ================================================== */
+
+static int
+is_step_limit_reached(double offset, double offset_correction)
+{
+  if (make_step_limit == 0) {
+    return 0;
+  } else if (make_step_limit > 0) {
+    make_step_limit--;
+  }
+  return fabs(offset - offset_correction) > make_step_threshold;
+}
+
+/* ================================================== */
+
+static int
+is_offset_ok(double offset)
+{
+  if (max_offset_delay < 0)
+    return 1;
+
+  if (max_offset_delay > 0) {
+    max_offset_delay--;
+    return 1;
+  }
+
+  offset = fabs(offset);
+  if (offset > max_offset) {
+    LOG(LOGS_WARN, 
+        "Adjustment of %.3f seconds exceeds the allowed maximum of %.3f seconds (%s) ",
+        -offset, max_offset, !max_offset_ignore ? "exiting" : "ignored");
+    if (!max_offset_ignore)
+      end_ref_mode(0);
+    else if (max_offset_ignore > 0)
+      max_offset_ignore--;
+    return 0;
+  }
+  return 1;
+}
+
+/* ================================================== */
+
+static int
+is_leap_second_day(time_t when)
+{
+  struct tm *stm;
+
+  stm = gmtime(&when);
+  if (!stm)
+    return 0;
+
+  /* Allow leap second only on the last day of June and December */
+  return (stm->tm_mon == 5 && stm->tm_mday == 30) ||
+         (stm->tm_mon == 11 && stm->tm_mday == 31);
+}
+
+/* ================================================== */
+
+static NTP_Leap
+get_tz_leap(time_t when, int *tai_offset)
+{
+  static time_t last_tz_leap_check;
+  static NTP_Leap tz_leap;
+  static int tz_tai_offset;
+
+  struct tm stm, *tm;
+  time_t t;
+  char *tz_env, tz_orig[128];
+
+  *tai_offset = tz_tai_offset;
+
+  /* Do this check at most twice a day */
+  when = when / (12 * 3600) * (12 * 3600);
+  if (last_tz_leap_check == when)
+      return tz_leap;
+
+  last_tz_leap_check = when;
+  tz_leap = LEAP_Normal;
+  tz_tai_offset = 0;
+
+  tm = gmtime(&when);
+  if (!tm)
+    return tz_leap;
+
+  stm = *tm;
+
+  /* Temporarily switch to the timezone containing leap seconds */
+  tz_env = getenv("TZ");
+  if (tz_env) {
+    if (strlen(tz_env) >= sizeof (tz_orig))
+      return tz_leap;
+    strcpy(tz_orig, tz_env);
+  }
+  setenv("TZ", leap_tzname, 1);
+  tzset();
+
+  /* Get the TAI-UTC offset, which started at the epoch at 10 seconds */
+  t = mktime(&stm);
+  if (t != -1)
+    tz_tai_offset = t - when + 10;
+
+  /* Set the time to 23:59:60 and see how it overflows in mktime() */
+  stm.tm_sec = 60;
+  stm.tm_min = 59;
+  stm.tm_hour = 23;
+
+  t = mktime(&stm);
+
+  if (tz_env)
+    setenv("TZ", tz_orig, 1);
+  else
+    unsetenv("TZ");
+  tzset();
+
+  if (t == -1)
+    return tz_leap;
+
+  if (stm.tm_sec == 60)
+    tz_leap = LEAP_InsertSecond;
+  else if (stm.tm_sec == 1)
+    tz_leap = LEAP_DeleteSecond;
+
+  *tai_offset = tz_tai_offset;
+
+  return tz_leap;
+}
+
+/* ================================================== */
+
+static void
+leap_end_timeout(void *arg)
+{
+  leap_timeout_id = 0;
+  leap_in_progress = 0;
+
+  if (our_tai_offset)
+    our_tai_offset += our_leap_sec;
+  our_leap_sec = 0;
+
+  if (leap_mode == REF_LeapModeSystem)
+    LCL_SetSystemLeap(our_leap_sec, our_tai_offset);
+
+  if (our_leap_status == LEAP_InsertSecond ||
+      our_leap_status == LEAP_DeleteSecond)
+    our_leap_status = LEAP_Normal;
+}
+
+/* ================================================== */
+
+static void
+leap_start_timeout(void *arg)
+{
+  leap_in_progress = 1;
+
+  switch (leap_mode) {
+    case REF_LeapModeSystem:
+      DEBUG_LOG("Waiting for system clock leap second correction");
+      break;
+    case REF_LeapModeSlew:
+      LCL_NotifyLeap(our_leap_sec);
+      LCL_AccumulateOffset(our_leap_sec, 0.0);
+      LOG(LOGS_WARN, "Adjusting system clock for leap second");
+      break;
+    case REF_LeapModeStep:
+      LCL_NotifyLeap(our_leap_sec);
+      LCL_ApplyStepOffset(our_leap_sec);
+      LOG(LOGS_WARN, "System clock was stepped for leap second");
+      break;
+    case REF_LeapModeIgnore:
+      LOG(LOGS_WARN, "Ignoring leap second");
+      break;
+    default:
+      break;
+  }
+
+  /* Wait until the leap second is over with some extra room to be safe */
+  leap_timeout_id = SCH_AddTimeoutByDelay(2.0, leap_end_timeout, NULL);
+}
+
+/* ================================================== */
+
+static void
+set_leap_timeout(time_t now)
+{
+  struct timespec when;
+
+  /* Stop old timer if there is one */
+  SCH_RemoveTimeout(leap_timeout_id);
+  leap_timeout_id = 0;
+  leap_in_progress = 0;
+
+  if (!our_leap_sec)
+    return;
+
+  /* Insert leap second at 0:00:00 UTC, delete at 23:59:59 UTC.  If the clock
+     will be corrected by the system, timeout slightly sooner to be sure it
+     will happen before the system correction. */
+  when.tv_sec = (now / (24 * 3600) + 1) * (24 * 3600);
+  when.tv_nsec = 0;
+  if (our_leap_sec < 0)
+    when.tv_sec--;
+  if (leap_mode == REF_LeapModeSystem) {
+    when.tv_sec--;
+    when.tv_nsec = 500000000;
+  }
+
+  leap_timeout_id = SCH_AddTimeout(&when, leap_start_timeout, NULL);
+}
+
+/* ================================================== */
+
+static void
+update_leap_status(NTP_Leap leap, time_t now, int reset)
+{
+  NTP_Leap tz_leap;
+  int leap_sec, tai_offset;
+
+  leap_sec = 0;
+  tai_offset = 0;
+
+  if (leap_tzname && now) {
+    tz_leap = get_tz_leap(now, &tai_offset);
+    if (leap == LEAP_Normal)
+      leap = tz_leap;
+  }
+
+  if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
+    /* Check that leap second is allowed today */
+
+    if (is_leap_second_day(now)) {
+      if (leap == LEAP_InsertSecond) {
+        leap_sec = 1;
+      } else {
+        leap_sec = -1;
+      }
+    } else {
+      leap = LEAP_Normal;
+    }
+  }
+  
+  if ((leap_sec != our_leap_sec || tai_offset != our_tai_offset)
+      && !REF_IsLeapSecondClose()) {
+    our_leap_sec = leap_sec;
+    our_tai_offset = tai_offset;
+
+    switch (leap_mode) {
+      case REF_LeapModeSystem:
+        LCL_SetSystemLeap(our_leap_sec, our_tai_offset);
+        /* Fall through */
+      case REF_LeapModeSlew:
+      case REF_LeapModeStep:
+      case REF_LeapModeIgnore:
+        set_leap_timeout(now);
+        break;
+      default:
+        assert(0);
+        break;
+    }
+  } else if (reset) {
+    set_leap_timeout(now);
+  }
+
+  our_leap_status = leap;
+}
+
+/* ================================================== */
+
+static double
+get_root_dispersion(struct timespec *ts)
+{
+  if (UTI_IsZeroTimespec(&our_ref_time))
+    return 1.0;
+
+  return our_root_dispersion +
+         fabs(UTI_DiffTimespecsToDouble(ts, &our_ref_time)) *
+         (our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError());
+}
+
+/* ================================================== */
+
+static void
+write_log(struct timespec *now, int combined_sources, double freq,
+          double offset, double offset_sd, double uncorrected_offset,
+          double orig_root_distance)
+{
+  const char leap_codes[4] = {'N', '+', '-', '?'};
+  double root_dispersion, max_error;
+  static double last_sys_offset = 0.0;
+
+  if (logfileid == -1)
+    return;
+
+  max_error = orig_root_distance + fabs(last_sys_offset);
+  root_dispersion = get_root_dispersion(now);
+  last_sys_offset = offset - uncorrected_offset;
+
+  LOG_FileWrite(logfileid,
+                "%s %-15s %2d %10.3f %10.3f %10.3e %1c %2d %10.3e %10.3e %10.3e %10.3e %10.3e",
+                UTI_TimeToLogForm(now->tv_sec),
+                our_ref_ip.family != IPADDR_UNSPEC ?
+                  UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
+                our_stratum, freq, 1.0e6 * our_skew, offset,
+                leap_codes[our_leap_status], combined_sources, offset_sd,
+                uncorrected_offset, our_root_delay, root_dispersion, max_error);
+}
+
+/* ================================================== */
+
+static void
+special_mode_sync(int valid, double offset)
+{
+  int step;
+
+  switch (mode) {
+    case REF_ModeInitStepSlew:
+      if (!valid) {
+        LOG(LOGS_WARN, "No suitable source for initstepslew");
+        end_ref_mode(0);
+        break;
+      }
+
+      step = fabs(offset) >= CNF_GetInitStepThreshold();
+
+      LOG(LOGS_INFO, "System's initial offset : %.6f seconds %s of true (%s)",
+          fabs(offset), offset >= 0 ? "fast" : "slow", step ? "step" : "slew");
+
+      if (step)
+        LCL_ApplyStepOffset(offset);
+      else
+        LCL_AccumulateOffset(offset, 0.0);
+
+      end_ref_mode(1);
+
+      break;
+    case REF_ModeUpdateOnce:
+    case REF_ModePrintOnce:
+      if (!valid) {
+        LOG(LOGS_WARN, "No suitable source for synchronisation");
+        end_ref_mode(0);
+        break;
+      }
+
+      step = mode == REF_ModeUpdateOnce;
+
+      LOG(LOGS_INFO, "System clock wrong by %.6f seconds (%s)",
+          -offset, step ? "step" : "ignored");
+
+      if (step)
+        LCL_ApplyStepOffset(offset);
+
+      end_ref_mode(1);
+
+      break;
+    case REF_ModeIgnore:
+      /* Do nothing until the mode is changed */
+      break;
+    default:
+      assert(0);
+  }
+}
+
+/* ================================================== */
+
+void
+REF_SetReference(int stratum,
+                 NTP_Leap leap,
+                 int combined_sources,
+                 uint32_t ref_id,
+                 IPAddr *ref_ip,
+                 struct timespec *ref_time,
+                 double offset,
+                 double offset_sd,
+                 double frequency,
+                 double skew,
+                 double root_delay,
+                 double root_dispersion
+                 )
+{
+  double previous_skew, new_skew;
+  double previous_freq, new_freq;
+  double old_weight, new_weight, sum_weight;
+  double delta_freq1, delta_freq2;
+  double skew1, skew2;
+  double our_offset;
+  double our_frequency;
+  double abs_freq_ppm;
+  double update_interval;
+  double elapsed, correction_rate, orig_root_distance;
+  double uncorrected_offset, accumulate_offset, step_offset;
+  struct timespec now, raw_now;
+  NTP_int64 ref_fuzz;
+
+  assert(initialised);
+
+  /* Special modes are implemented elsewhere */
+  if (mode != REF_ModeNormal) {
+    special_mode_sync(1, offset);
+    return;
+  }
+
+  /* Guard against dividing by zero and NaN */
+  if (!(skew > MIN_SKEW))
+    skew = MIN_SKEW;
+
+  LCL_ReadRawTime(&raw_now);
+  LCL_GetOffsetCorrection(&raw_now, &uncorrected_offset, NULL);
+  UTI_AddDoubleToTimespec(&raw_now, uncorrected_offset, &now);
+
+  elapsed = UTI_DiffTimespecsToDouble(&now, ref_time);
+  our_offset = offset + elapsed * frequency;
+
+  if (!is_offset_ok(our_offset))
+    return;
+
+  orig_root_distance = our_root_delay / 2.0 + get_root_dispersion(&now);
+
+  are_we_synchronised = leap != LEAP_Unsynchronised ? 1 : 0;
+  our_stratum = stratum + 1;
+  our_ref_id = ref_id;
+  if (ref_ip)
+    our_ref_ip = *ref_ip;
+  else
+    our_ref_ip.family = IPADDR_UNSPEC;
+  our_ref_time = *ref_time;
+  our_root_delay = root_delay;
+  our_root_dispersion = root_dispersion;
+
+  if (last_ref_update.tv_sec) {
+    update_interval = UTI_DiffTimespecsToDouble(&now, &last_ref_update);
+    if (update_interval < 0.0)
+      update_interval = 0.0;
+  } else {
+    update_interval = 0.0;
+  }
+  last_ref_update = now;
+
+  /* We want to correct the offset quickly, but we also want to keep the
+     frequency error caused by the correction itself low.
+
+     Define correction rate as the area of the region bounded by the graph of
+     offset corrected in time. Set the rate so that the time needed to correct
+     an offset equal to the current sourcestats stddev will be equal to the
+     update interval multiplied by the correction time ratio (assuming linear
+     adjustment). The offset and the time needed to make the correction are
+     inversely proportional.
+
+     This is only a suggestion and it's up to the system driver how the
+     adjustment will be executed. */
+
+  correction_rate = correction_time_ratio * 0.5 * offset_sd * update_interval;
+
+  /* Check if the clock should be stepped */
+  if (is_step_limit_reached(our_offset, uncorrected_offset)) {
+    /* Cancel the uncorrected offset and correct the total offset by step */
+    accumulate_offset = uncorrected_offset;
+    step_offset = our_offset - uncorrected_offset;
+  } else {
+    accumulate_offset = our_offset;
+    step_offset = 0.0;
+  }
+
+  /* Eliminate updates that are based on totally unreliable frequency
+     information. Ignore this limit with manual reference. */
+
+  if (fabs(skew) < max_update_skew || leap == LEAP_Unsynchronised) {
+
+    previous_skew = our_skew;
+    new_skew = skew;
+
+    previous_freq = 0.0; /* We assume that the local clock is running
+                          according to our previously determined
+                          value; note that this is a delta frequency
+                          --- absolute frequencies are only known in
+                          the local module. */
+    new_freq = frequency;
+
+    /* Set new frequency based on weighted average of old and new skew. With
+       manual reference the old frequency has no weight. */
+
+    old_weight = leap != LEAP_Unsynchronised ? 1.0 / Sqr(previous_skew) : 0.0;
+    new_weight = 3.0 / Sqr(new_skew);
+
+    sum_weight = old_weight + new_weight;
+
+    our_frequency = (previous_freq * old_weight + new_freq * new_weight) / sum_weight;
+
+    delta_freq1 = previous_freq - our_frequency;
+    delta_freq2 = new_freq - our_frequency;
+
+    skew1 = sqrt((Sqr(delta_freq1) * old_weight + Sqr(delta_freq2) * new_weight) / sum_weight);
+    skew2 = (previous_skew * old_weight + new_skew * new_weight) / sum_weight;
+    our_skew = skew1 + skew2;
+
+    our_residual_freq = new_freq - our_frequency;
+
+    LCL_AccumulateFrequencyAndOffset(our_frequency, accumulate_offset, correction_rate);
+    
+  } else {
+    DEBUG_LOG("Skew %f too large to track, offset=%f", skew, accumulate_offset);
+
+    LCL_AccumulateOffset(accumulate_offset, correction_rate);
+
+    our_residual_freq = frequency;
+  }
+
+  update_leap_status(leap, raw_now.tv_sec, 0);
+  maybe_log_offset(our_offset, raw_now.tv_sec);
+
+  if (step_offset != 0.0) {
+    if (LCL_ApplyStepOffset(step_offset))
+      LOG(LOGS_WARN, "System clock was stepped by %.6f seconds", -step_offset);
+  }
+
+  LCL_SetSyncStatus(are_we_synchronised, offset_sd, offset_sd + root_delay / 2.0 + root_dispersion);
+
+  /* Add a random error of up to one second to the reference time to make it
+     less useful when disclosed to NTP and cmdmon clients for estimating
+     receive timestamps in the interleaved symmetric NTP mode */
+  UTI_GetNtp64Fuzz(&ref_fuzz, 0);
+  UTI_TimespecToNtp64(&our_ref_time, &ref_fuzz, &ref_fuzz);
+  UTI_Ntp64ToTimespec(&ref_fuzz, &our_ref_time);
+  if (UTI_CompareTimespecs(&our_ref_time, ref_time) >= 0)
+    our_ref_time.tv_sec--;
+
+  abs_freq_ppm = LCL_ReadAbsoluteFrequency();
+
+  write_log(&now, combined_sources, abs_freq_ppm, our_offset, offset_sd,
+            uncorrected_offset, orig_root_distance);
+
+  if (drift_file) {
+    /* Update drift file at most once per hour */
+    drift_file_age += update_interval;
+    if (drift_file_age < 0.0 || drift_file_age > 3600.0) {
+      update_drift_file(abs_freq_ppm, our_skew);
+      drift_file_age = 0.0;
+    }
+  }
+
+  /* Update fallback drifts */
+  if (fb_drifts && are_we_synchronised) {
+    update_fb_drifts(abs_freq_ppm, update_interval);
+    schedule_fb_drift(&now);
+  }
+
+  last_ref_update_interval = update_interval;
+  last_offset = our_offset;
+
+  /* Update the moving average of squares of offset, quickly on start */
+  if (avg2_moving) {
+    avg2_offset += 0.1 * (our_offset * our_offset - avg2_offset);
+  } else {
+    if (avg2_offset > 0.0 && avg2_offset < our_offset * our_offset)
+      avg2_moving = 1;
+    avg2_offset = our_offset * our_offset;
+  }
+}
+
+/* ================================================== */
+
+void
+REF_SetManualReference
+(
+ struct timespec *ref_time,
+ double offset,
+ double frequency,
+ double skew
+)
+{
+  /* We are not synchronised to an external source, as such.  This is
+     only supposed to be used with the local source option, really.
+     Log as MANU in the tracking log, packets will have NTP_REFID_LOCAL. */
+  REF_SetReference(0, LEAP_Unsynchronised, 1, 0x4D414E55UL, NULL,
+                   ref_time, offset, 0.0, frequency, skew, 0.0, 0.0);
+}
+
+/* ================================================== */
+
+void
+REF_SetUnsynchronised(void)
+{
+  /* Variables required for logging to statistics log */
+  struct timespec now, now_raw;
+  double uncorrected_offset;
+
+  assert(initialised);
+
+  /* Special modes are implemented elsewhere */
+  if (mode != REF_ModeNormal) {
+    special_mode_sync(0, 0.0);
+    return;
+  }
+
+  LCL_ReadRawTime(&now_raw);
+  LCL_GetOffsetCorrection(&now_raw, &uncorrected_offset, NULL);
+  UTI_AddDoubleToTimespec(&now_raw, uncorrected_offset, &now);
+
+  if (fb_drifts) {
+    schedule_fb_drift(&now);
+  }
+
+  update_leap_status(LEAP_Unsynchronised, 0, 0);
+  our_ref_ip.family = IPADDR_INET4;
+  our_ref_ip.addr.in4 = 0;
+  our_stratum = 0;
+  are_we_synchronised = 0;
+
+  LCL_SetSyncStatus(0, 0.0, 0.0);
+
+  write_log(&now, 0, LCL_ReadAbsoluteFrequency(), 0.0, 0.0, uncorrected_offset,
+            our_root_delay / 2.0 + get_root_dispersion(&now));
+}
+
+/* ================================================== */
+
+void
+REF_GetReferenceParams
+(
+ struct timespec *local_time,
+ int *is_synchronised,
+ NTP_Leap *leap_status,
+ int *stratum,
+ uint32_t *ref_id,
+ struct timespec *ref_time,
+ double *root_delay,
+ double *root_dispersion
+)
+{
+  double dispersion;
+
+  assert(initialised);
+
+  if (are_we_synchronised) {
+    dispersion = get_root_dispersion(local_time);
+  } else {
+    dispersion = 0.0;
+  }
+
+  /* Local reference is active when enabled and the clock is not synchronised
+     or the root distance exceeds the threshold */
+
+  if (are_we_synchronised &&
+      !(enable_local_stratum && our_root_delay / 2 + dispersion > local_distance)) {
+
+    *is_synchronised = 1;
+
+    *stratum = our_stratum;
+
+    *leap_status = !leap_in_progress ? our_leap_status : LEAP_Unsynchronised;
+    *ref_id = our_ref_id;
+    *ref_time = our_ref_time;
+    *root_delay = our_root_delay;
+    *root_dispersion = dispersion;
+
+  } else if (enable_local_stratum) {
+
+    *is_synchronised = 0;
+
+    *stratum = local_stratum;
+    *ref_id = NTP_REFID_LOCAL;
+    /* Make the reference time be now less a second - this will
+       scarcely affect the client, but will ensure that the transmit
+       timestamp cannot come before this (which would cause test 7 to
+       fail in the client's read routine) if the local system clock's
+       read routine is broken in any way. */
+    *ref_time = *local_time;
+    --ref_time->tv_sec;
+
+    /* Not much else we can do for leap second bits - maybe need to
+       have a way for the administrator to feed leap bits in */
+    *leap_status = LEAP_Normal;
+    
+    *root_delay = 0.0;
+    *root_dispersion = 0.0;
+    
+  } else {
+
+    *is_synchronised = 0;
+
+    *leap_status = LEAP_Unsynchronised;
+    *stratum = NTP_MAX_STRATUM;
+    *ref_id = NTP_REFID_UNSYNC;
+    UTI_ZeroTimespec(ref_time);
+    /* These values seem to be standard for a client, and
+       any peer or client of ours will ignore them anyway because
+       we don't claim to be synchronised */
+    *root_dispersion = 1.0;
+    *root_delay = 1.0;
+
+  }
+}
+
+/* ================================================== */
+
+int
+REF_GetOurStratum(void)
+{
+  struct timespec now_cooked, ref_time;
+  int synchronised, stratum;
+  NTP_Leap leap_status;
+  uint32_t ref_id;
+  double root_delay, root_dispersion;
+
+  SCH_GetLastEventTime(&now_cooked, NULL, NULL);
+  REF_GetReferenceParams(&now_cooked, &synchronised, &leap_status, &stratum,
+                         &ref_id, &ref_time, &root_delay, &root_dispersion);
+
+  return stratum;
+}
+
+/* ================================================== */
+
+int
+REF_GetOrphanStratum(void)
+{
+  if (!enable_local_stratum || !local_orphan || mode != REF_ModeNormal)
+    return NTP_MAX_STRATUM;
+  return local_stratum;
+}
+
+/* ================================================== */
+
+double
+REF_GetSkew(void)
+{
+  return our_skew;
+}
+
+/* ================================================== */
+
+void
+REF_ModifyMaxupdateskew(double new_max_update_skew)
+{
+  max_update_skew = new_max_update_skew * 1.0e-6;
+}
+
+/* ================================================== */
+
+void
+REF_ModifyMakestep(int limit, double threshold)
+{
+  make_step_limit = limit;
+  make_step_threshold = threshold;
+}
+
+/* ================================================== */
+
+void
+REF_EnableLocal(int stratum, double distance, int orphan)
+{
+  enable_local_stratum = 1;
+  local_stratum = CLAMP(1, stratum, NTP_MAX_STRATUM - 1);
+  local_distance = distance;
+  local_orphan = !!orphan;
+}
+
+/* ================================================== */
+
+void
+REF_DisableLocal(void)
+{
+  enable_local_stratum = 0;
+}
+
+/* ================================================== */
+
+#define LEAP_SECOND_CLOSE 5
+
+int REF_IsLeapSecondClose(void)
+{
+  struct timespec now, now_raw;
+  time_t t;
+
+  if (!our_leap_sec)
+    return 0;
+
+  SCH_GetLastEventTime(&now, NULL, &now_raw);
+
+  t = now.tv_sec > 0 ? now.tv_sec : -now.tv_sec;
+  if ((t + LEAP_SECOND_CLOSE) % (24 * 3600) < 2 * LEAP_SECOND_CLOSE)
+    return 1;
+
+  t = now_raw.tv_sec > 0 ? now_raw.tv_sec : -now_raw.tv_sec;
+  if ((t + LEAP_SECOND_CLOSE) % (24 * 3600) < 2 * LEAP_SECOND_CLOSE)
+    return 1;
+
+  return 0;
+}
+
+/* ================================================== */
+
+int
+REF_GetTaiOffset(struct timespec *ts)
+{
+  int tai_offset;
+
+  get_tz_leap(ts->tv_sec, &tai_offset);
+
+  return tai_offset;
+}
+
+/* ================================================== */
+
+void
+REF_GetTrackingReport(RPT_TrackingReport *rep)
+{
+  struct timespec now_raw, now_cooked;
+  double correction;
+  int synchronised;
+
+  LCL_ReadRawTime(&now_raw);
+  LCL_GetOffsetCorrection(&now_raw, &correction, NULL);
+  UTI_AddDoubleToTimespec(&now_raw, correction, &now_cooked);
+
+  REF_GetReferenceParams(&now_cooked, &synchronised,
+                         &rep->leap_status, &rep->stratum,
+                         &rep->ref_id, &rep->ref_time,
+                         &rep->root_delay, &rep->root_dispersion);
+
+  if (rep->stratum == NTP_MAX_STRATUM && !synchronised)
+    rep->stratum = 0;
+
+  rep->ip_addr.family = IPADDR_UNSPEC;
+  rep->current_correction = correction;
+  rep->freq_ppm = LCL_ReadAbsoluteFrequency();
+  rep->resid_freq_ppm = 0.0;
+  rep->skew_ppm = 0.0;
+  rep->last_update_interval = last_ref_update_interval;
+  rep->last_offset = last_offset;
+  rep->rms_offset = sqrt(avg2_offset);
+
+  if (synchronised) {
+    rep->ip_addr = our_ref_ip;
+    rep->resid_freq_ppm = 1.0e6 * our_residual_freq;
+    rep->skew_ppm = 1.0e6 * our_skew;
+  }
+}
diff --git a/chrony_3_3/reference.h b/chrony_3_3/reference.h
new file mode 100644
index 0000000..6ee4953
--- /dev/null
+++ b/chrony_3_3/reference.h
@@ -0,0 +1,192 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2002
+ * 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  This is the header file for the module that keeps track of the current
+  reference.
+
+  */
+
+#ifndef GOT_REFERENCE_H
+#define GOT_REFERENCE_H
+
+#include "sysincl.h"
+
+#include "ntp.h"
+#include "reports.h"
+
+/* Leap second handling modes */
+typedef enum {
+  REF_LeapModeSystem,
+  REF_LeapModeSlew,
+  REF_LeapModeStep,
+  REF_LeapModeIgnore,
+} REF_LeapMode;
+
+/* Init function */
+extern void REF_Initialise(void);
+
+/* Fini function */
+extern void REF_Finalise(void);
+
+typedef enum {
+  REF_ModeNormal,
+  REF_ModeInitStepSlew,
+  REF_ModeUpdateOnce,
+  REF_ModePrintOnce,
+  REF_ModeIgnore,
+} REF_Mode;
+
+/* Set reference update mode */
+extern void REF_SetMode(REF_Mode mode);
+
+/* Get reference update mode */
+extern REF_Mode REF_GetMode(void);
+
+/* Function type for handlers to be called back when mode ends */
+typedef void (*REF_ModeEndHandler)(int result);
+
+/* Set the handler for being notified of mode ending */
+extern void REF_SetModeEndHandler(REF_ModeEndHandler handler);
+
+/* Get leap second handling mode */
+extern REF_LeapMode REF_GetLeapMode(void);
+
+/* Function which takes a local cooked time and returns the estimated
+   time of the reference.  It also returns the other parameters
+   required for forming the outgoing NTP packet.
+
+   local_time is the cooked local time returned by the LCL module
+
+   is_synchronised indicates whether we are synchronised to anything
+   at the moment.
+
+   leap indicates the current leap status
+
+   stratum is the stratum of this machine, when considered to be sync'd to the
+   reference
+   
+   ref_id is the reference_id of the source
+
+   ref_time is the time at which the we last set the reference source up
+
+   root_delay is the root delay of the sample we are using
+
+   root_dispersion is the root dispersion of the sample we are using, with all the
+   skew etc added on.
+
+   */
+
+extern void REF_GetReferenceParams
+(
+ struct timespec *local_time,
+ int *is_synchronised,
+ NTP_Leap *leap,
+ int *stratum,
+ uint32_t *ref_id,
+ struct timespec *ref_time,
+ double *root_delay,
+ double *root_dispersion
+);
+
+/* Function called by the clock selection process to register a new
+   reference source and its parameters
+
+   stratum is the stratum of the reference
+
+   leap is the leap status read from the source
+
+   ref_id is the reference id of the reference
+
+   ref_time is the time at which the parameters are assumed to be
+   correct, in terms of local time
+
+   frequency is the amount of local clock gain relative to the
+   reference per unit time interval of the local clock
+
+   skew is the maximum estimated frequency error (so we are within
+   [frequency+-skew])
+
+   root_delay is the root delay of the sample we are using
+
+   root_dispersion is the root dispersion of the sample we are using
+
+   */
+
+extern void REF_SetReference
+(
+ int stratum,
+ NTP_Leap leap,
+ int combined_sources,
+ uint32_t ref_id,
+ IPAddr *ref_ip,
+ struct timespec *ref_time,
+ double offset,
+ double offset_sd,
+ double frequency,
+ double skew,
+ double root_delay,
+ double root_dispersion
+);
+
+extern void REF_SetManualReference
+(
+ struct timespec *ref_time,
+ double offset,
+ double frequency,
+ double skew
+);
+
+/* Mark the local clock as unsynchronised */
+extern void
+REF_SetUnsynchronised(void);
+
+/* Return the current stratum of this host or 16 if the host is not
+   synchronised */
+extern int REF_GetOurStratum(void);
+
+/* Return stratum of the local reference if orphan mode is enabled */
+extern int REF_GetOrphanStratum(void);
+
+/* Return the current skew */
+extern double REF_GetSkew(void);
+
+/* Modify the setting for the maximum skew we are prepared to allow updates on (in ppm). */
+extern void REF_ModifyMaxupdateskew(double new_max_update_skew);
+
+/* Modify makestep settings */
+extern void REF_ModifyMakestep(int limit, double threshold);
+
+extern void REF_EnableLocal(int stratum, double distance, int orphan);
+extern void REF_DisableLocal(void);
+
+/* Check if current raw or cooked time is close to a leap second
+   and is better to discard any measurements */
+extern int REF_IsLeapSecondClose(void);
+
+/* Return TAI-UTC offset corresponding to a time in UTC if available */
+extern int REF_GetTaiOffset(struct timespec *ts);
+
+extern void REF_GetTrackingReport(RPT_TrackingReport *rep);
+
+#endif /* GOT_REFERENCE_H */
diff --git a/chrony_3_3/regress.c b/chrony_3_3/regress.c
new file mode 100644
index 0000000..e767e2f
--- /dev/null
+++ b/chrony_3_3/regress.c
@@ -0,0 +1,704 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2011, 2016-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Regression algorithms.
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "regress.h"
+#include "logging.h"
+#include "util.h"
+
+#define MAX_POINTS 64
+
+void
+RGR_WeightedRegression
+(double *x,                     /* independent variable */
+ double *y,                     /* measured data */
+ double *w,                     /* weightings (large => data
+                                   less reliable) */
+ 
+ int n,                         /* number of data points */
+
+ /* And now the results */
+
+ double *b0,                    /* estimated y axis intercept */
+ double *b1,                    /* estimated slope */
+ double *s2,                    /* estimated variance of data points */
+ 
+ double *sb0,                   /* estimated standard deviation of
+                                   intercept */
+ double *sb1                    /* estimated standard deviation of
+                                   slope */
+
+ /* Could add correlation stuff later if required */
+)
+{
+  double P, Q, U, V, W;
+  double diff;
+  double u, ui, aa;
+  int i;
+
+  assert(n >= 3);
+
+  W = U = 0;
+  for (i=0; i<n; i++) {
+    U += x[i]        / w[i];
+    W += 1.0         / w[i];
+  }
+
+  u = U / W;
+
+  /* Calculate statistics from data */
+  P = Q = V = 0.0;
+  for (i=0; i<n; i++) {
+    ui = x[i] - u;
+    P += y[i]        / w[i];
+    Q += y[i] * ui   / w[i];
+    V += ui   * ui   / w[i];
+  }
+
+  *b1 = Q / V;
+  *b0 = (P / W) - (*b1) * u;
+
+  *s2 = 0.0;
+  for (i=0; i<n; i++) {
+    diff = y[i] - *b0 - *b1*x[i];
+    *s2 += diff*diff / w[i];
+  }
+
+  *s2 /= (double)(n-2);
+
+  *sb1 = sqrt(*s2 / V);
+  aa = u * (*sb1);
+  *sb0 = sqrt(*s2 / W + aa * aa);
+
+  *s2 *= (n / W); /* Giving weighted average of variances */
+}
+
+/* ================================================== */
+/* Get the coefficient to multiply the standard deviation by, to get a
+   particular size of confidence interval (assuming a t-distribution) */
+  
+double
+RGR_GetTCoef(int dof)
+{
+  /* Assuming now the 99.95% quantile */
+  static const float coefs[] =
+  { 636.6, 31.6, 12.92, 8.61, 6.869,
+    5.959, 5.408, 5.041, 4.781, 4.587,
+    4.437, 4.318, 4.221, 4.140, 4.073,
+    4.015, 3.965, 3.922, 3.883, 3.850,
+    3.819, 3.792, 3.768, 3.745, 3.725,
+    3.707, 3.690, 3.674, 3.659, 3.646,
+    3.633, 3.622, 3.611, 3.601, 3.591,
+    3.582, 3.574, 3.566, 3.558, 3.551};
+
+  if (dof <= 40) {
+    return coefs[dof-1];
+  } else {
+    return 3.5; /* Until I can be bothered to do something better */
+  }
+}
+
+/* ================================================== */
+/* Get 90% quantile of chi-square distribution */
+
+double
+RGR_GetChi2Coef(int dof)
+{
+  static const float coefs[] = {
+    2.706, 4.605, 6.251, 7.779, 9.236, 10.645, 12.017, 13.362,
+    14.684, 15.987, 17.275, 18.549, 19.812, 21.064, 22.307, 23.542,
+    24.769, 25.989, 27.204, 28.412, 29.615, 30.813, 32.007, 33.196,
+    34.382, 35.563, 36.741, 37.916, 39.087, 40.256, 41.422, 42.585,
+    43.745, 44.903, 46.059, 47.212, 48.363, 49.513, 50.660, 51.805,
+    52.949, 54.090, 55.230, 56.369, 57.505, 58.641, 59.774, 60.907,
+    62.038, 63.167, 64.295, 65.422, 66.548, 67.673, 68.796, 69.919,
+    71.040, 72.160, 73.279, 74.397, 75.514, 76.630, 77.745, 78.860
+  };
+
+  if (dof <= 64) {
+    return coefs[dof-1];
+  } else {
+    return 1.2 * dof; /* Until I can be bothered to do something better */
+  }
+}
+
+/* ================================================== */
+/* Critical value for number of runs of residuals with same sign.
+   5% critical region for now. */
+
+static char critical_runs[] = {
+  0,  0,  0,  0,  0,  0,  0,  0,  2,  3,
+  3,  3,  4,  4,  5,  5,  5,  6,  6,  7,
+  7,  7,  8,  8,  9,  9,  9, 10, 10, 11,
+ 11, 11, 12, 12, 13, 13, 14, 14, 14, 15,
+ 15, 16, 16, 17, 17, 18, 18, 18, 19, 19,
+ 20, 20, 21, 21, 21, 22, 22, 23, 23, 24,
+ 24, 25, 25, 26, 26, 26, 27, 27, 28, 28,
+ 29, 29, 30, 30, 30, 31, 31, 32, 32, 33,
+ 33, 34, 34, 35, 35, 35, 36, 36, 37, 37,
+ 38, 38, 39, 39, 40, 40, 40, 41, 41, 42,
+ 42, 43, 43, 44, 44, 45, 45, 46, 46, 46,
+ 47, 47, 48, 48, 49, 49, 50, 50, 51, 51,
+ 52, 52, 52, 53, 53, 54, 54, 55, 55, 56
+};
+
+/* ================================================== */
+
+static int
+n_runs_from_residuals(double *resid, int n)
+{
+  int nruns;
+  int i;
+  
+  nruns = 1;
+  for (i=1; i<n; i++) {
+    if (((resid[i-1] < 0.0) && (resid[i] < 0.0)) ||
+        ((resid[i-1] > 0.0) && (resid[i] > 0.0))) {
+      /* Nothing to do */
+    } else {
+      nruns++;
+    }
+  }
+  
+  return nruns;
+}
+
+/* ================================================== */
+/* Return a boolean indicating whether we had enough points for
+   regression */
+
+int
+RGR_FindBestRegression 
+(double *x,                     /* independent variable */
+ double *y,                     /* measured data */
+ double *w,                     /* weightings (large => data
+                                   less reliable) */
+ 
+ int n,                         /* number of data points */
+ int m,                         /* number of extra samples in x and y arrays
+                                   (negative index) which can be used to
+                                   extend runs test */
+ int min_samples,               /* minimum number of samples to be kept after
+                                   changing the starting index to pass the runs
+                                   test */
+
+ /* And now the results */
+
+ double *b0,                    /* estimated y axis intercept */
+ double *b1,                    /* estimated slope */
+ double *s2,                    /* estimated variance of data points */
+ 
+ double *sb0,                   /* estimated standard deviation of
+                                   intercept */
+ double *sb1,                   /* estimated standard deviation of
+                                   slope */
+
+ int *new_start,                /* the new starting index to make the
+                                   residuals pass the two tests */
+ 
+ int *n_runs,                   /* number of runs amongst the residuals */
+
+ int *dof                       /* degrees of freedom in statistics (needed
+                                   to get confidence intervals later) */
+
+)
+{
+  double P, Q, U, V, W; /* total */
+  double resid[MAX_POINTS * REGRESS_RUNS_RATIO];
+  double ss;
+  double a, b, u, ui, aa;
+
+  int start, resid_start, nruns, npoints;
+  int i;
+
+  assert(n <= MAX_POINTS && m >= 0);
+  assert(n * REGRESS_RUNS_RATIO < sizeof (critical_runs) / sizeof (critical_runs[0]));
+
+  if (n < MIN_SAMPLES_FOR_REGRESS) {
+    return 0;
+  }
+
+  start = 0;
+  do {
+
+    W = U = 0;
+    for (i=start; i<n; i++) {
+      U += x[i]        / w[i];
+      W += 1.0         / w[i];
+    }
+
+    u = U / W;
+
+    P = Q = V = 0.0;
+    for (i=start; i<n; i++) {
+      ui = x[i] - u;
+      P += y[i]        / w[i];
+      Q += y[i] * ui   / w[i];
+      V += ui   * ui   / w[i];
+    }
+
+    b = Q / V;
+    a = (P / W) - (b * u);
+
+    /* Get residuals also for the extra samples before start */
+    resid_start = n - (n - start) * REGRESS_RUNS_RATIO;
+    if (resid_start < -m)
+      resid_start = -m;
+
+    for (i=resid_start; i<n; i++) {
+      resid[i - resid_start] = y[i] - a - b*x[i];
+    }
+
+    /* Count number of runs */
+    nruns = n_runs_from_residuals(resid, n - resid_start); 
+
+    if (nruns > critical_runs[n - resid_start] ||
+        n - start <= MIN_SAMPLES_FOR_REGRESS ||
+        n - start <= min_samples) {
+      if (start != resid_start) {
+        /* Ignore extra samples in returned nruns */
+        nruns = n_runs_from_residuals(resid + (start - resid_start), n - start);
+      }
+      break;
+    } else {
+      /* Try dropping one sample at a time until the runs test passes. */
+      ++start;
+    }
+
+  } while (1);
+
+  /* Work out statistics from full dataset */
+  *b1 = b;
+  *b0 = a;
+
+  ss = 0.0;
+  for (i=start; i<n; i++) {
+    ss += resid[i - resid_start]*resid[i - resid_start] / w[i];
+  }
+
+  npoints = n - start;
+  ss /= (double)(npoints - 2);
+  *sb1 = sqrt(ss / V);
+  aa = u * (*sb1);
+  *sb0 = sqrt((ss / W) + (aa * aa));
+  *s2 = ss * (double) npoints / W;
+
+  *new_start = start;
+  *dof = npoints - 2;
+  *n_runs = nruns;
+
+  return 1;
+
+}
+
+/* ================================================== */
+
+#define EXCH(a,b) temp=(a); (a)=(b); (b)=temp
+
+/* ================================================== */
+/* Find the index'th biggest element in the array x of n elements.
+   flags is an array where a 1 indicates that the corresponding entry
+   in x is known to be sorted into its correct position and a 0
+   indicates that the corresponding entry is not sorted.  However, if
+   flags[m] = flags[n] = 1 with m<n, then x[m] must be <= x[n] and for
+   all i with m<i<n, x[m] <= x[i] <= x[n].  In practice, this means
+   flags[] has to be the result of a previous call to this routine
+   with the same array x, and is used to remember which parts of the
+   x[] array we have already sorted.
+
+   The approach used is a cut-down quicksort, where we only bother to
+   keep sorting the partition that contains the index we are after.
+   The approach comes from Numerical Recipes in C (ISBN
+   0-521-43108-5). */
+
+static double
+find_ordered_entry_with_flags(double *x, int n, int index, char *flags)
+{
+  int u, v, l, r;
+  double temp;
+  double piv;
+  int pivind;
+
+  assert(index >= 0);
+
+  /* If this bit of the array is already sorted, simple! */
+  if (flags[index]) {
+    return x[index];
+  }
+  
+  /* Find subrange to look at */
+  u = v = index;
+  while (u > 0 && !flags[u]) u--;
+  if (flags[u]) u++;
+
+  while (v < (n-1) && !flags[v]) v++;
+  if (flags[v]) v--;
+
+  do {
+    if (v - u < 2) {
+      if (x[v] < x[u]) {
+        EXCH(x[v], x[u]);
+      }
+      flags[v] = flags[u] = 1;
+      return x[index];
+    } else { 
+      pivind = (u + v) >> 1;
+      EXCH(x[u], x[pivind]);
+      piv = x[u]; /* New value */
+      l = u + 1;
+      r = v;
+      do {
+        while (l < v && x[l] < piv) l++;
+        while (x[r] > piv) r--;
+        if (r <= l) break;
+        EXCH(x[l], x[r]);
+        l++;
+        r--;
+      } while (1);
+      EXCH(x[u], x[r]);
+      flags[r] = 1; /* Pivot now in correct place */
+      if (index == r) {
+        return x[r];
+      } else if (index < r) {
+        v = r - 1;
+      } else if (index > r) {
+        u = l;
+      }
+    }
+  } while (1);
+}
+
+/* ================================================== */
+
+#if 0
+/* Not used, but this is how it can be done */
+static double
+find_ordered_entry(double *x, int n, int index)
+{
+  char flags[MAX_POINTS];
+
+  memset(flags, 0, n * sizeof (flags[0]));
+  return find_ordered_entry_with_flags(x, n, index, flags);
+}
+#endif
+
+/* ================================================== */
+/* Find the median entry of an array x[] with n elements. */
+
+static double
+find_median(double *x, int n)
+{
+  int k;
+  char flags[MAX_POINTS];
+
+  memset(flags, 0, n * sizeof (flags[0]));
+  k = n>>1;
+  if (n&1) {
+    return find_ordered_entry_with_flags(x, n, k, flags);
+  } else {
+    return 0.5 * (find_ordered_entry_with_flags(x, n, k, flags) +
+                  find_ordered_entry_with_flags(x, n, k-1, flags));
+  }
+}
+
+/* ================================================== */
+
+double
+RGR_FindMedian(double *x, int n)
+{
+  double tmp[MAX_POINTS];
+
+  assert(n > 0 && n <= MAX_POINTS);
+  memcpy(tmp, x, n * sizeof (tmp[0]));
+
+  return find_median(tmp, n);
+}
+
+/* ================================================== */
+/* This function evaluates the equation
+
+   \sum_{i=0}^{n-1} x_i sign(y_i - a - b x_i)
+
+   and chooses the value of a that minimises the absolute value of the
+   result.  (See pp703-704 of Numerical Recipes in C). */
+
+static void
+eval_robust_residual
+(double *x,                     /* The independent points */
+ double *y,                     /* The dependent points */
+ int n,                         /* Number of points */
+ double b,                      /* Slope */
+ double *aa,                    /* Intercept giving smallest absolute
+                                   value for the above equation */
+ double *rr                     /* Corresponding value of equation */
+)
+{
+  int i;
+  double a, res, del;
+  double d[MAX_POINTS];
+
+  for (i=0; i<n; i++) {
+    d[i] = y[i] - b * x[i];
+  }
+  
+  a = find_median(d, n);
+
+  res = 0.0;
+  for (i=0; i<n; i++) {
+    del = y[i] - a - b * x[i];
+    if (del > 0.0) {
+      res += x[i];
+    } else if (del < 0.0) {
+      res -= x[i];
+    }
+  }
+
+  *aa = a;
+  *rr = res;
+}
+
+/* ================================================== */
+/* This routine performs a 'robust' regression, i.e. one which has low
+   susceptibility to outliers amongst the data.  If one thinks of a
+   normal (least squares) linear regression in 2D being analogous to
+   the arithmetic mean in 1D, this algorithm in 2D is roughly
+   analogous to the median in 1D.  This algorithm seems to work quite
+   well until the number of outliers is approximately half the number
+   of data points.
+
+   The return value is a status indicating whether there were enough
+   data points to run the routine or not. */
+
+int
+RGR_FindBestRobustRegression
+(double *x,                     /* The independent axis points */
+ double *y,                     /* The dependent axis points (which
+                                   may contain outliers). */
+ int n,                         /* The number of points */
+ double tol,                    /* The tolerance required in
+                                   determining the value of b1 */
+ double *b0,                    /* The estimated Y-axis intercept */
+ double *b1,                    /* The estimated slope */
+ int *n_runs,                   /* The number of runs of residuals */
+ int *best_start                /* The best starting index */
+)
+{
+  int i;
+  int start;
+  int n_points;
+  double a, b;
+  double P, U, V, W, X;
+  double resid, resids[MAX_POINTS];
+  double blo, bhi, bmid, rlo, rhi, rmid;
+  double s2, sb, incr;
+  double mx, dx, my, dy;
+  int nruns = 0;
+
+  assert(n <= MAX_POINTS);
+
+  if (n < 2) {
+    return 0;
+  } else if (n == 2) {
+    /* Just a straight line fit (we need this for the manual mode) */
+    *b1 = (y[1] - y[0]) / (x[1] - x[0]);
+    *b0 = y[0] - (*b1) * x[0];
+    *n_runs = 0;
+    *best_start = 0;
+    return 1;
+  }
+
+  /* else at least 3 points, apply normal algorithm */
+
+  start = 0;
+
+  /* Loop to strip oldest points that cause the regression residuals
+     to fail the number of runs test */
+  do {
+
+    n_points = n - start;
+
+    /* Use standard least squares regression to get starting estimate */
+
+    P = U = 0.0;
+    for (i=start; i<n; i++) {
+      P += y[i];
+      U += x[i];
+    }
+
+    W = (double) n_points;
+
+    my = P/W;
+    mx = U/W;
+
+    X = V = 0.0;
+    for (i=start; i<n; i++) {
+      dy = y[i] - my;
+      dx = x[i] - mx;
+      X += dy * dx;
+      V += dx * dx;
+    }
+
+    b = X / V;
+    a = my - b*mx;
+
+    s2 = 0.0;
+    for (i=start; i<n; i++) {
+      resid = y[i] - a - b * x[i];
+      s2 += resid * resid;
+    }
+
+    /* Need to expand range of b to get a root in the interval.
+       Estimate standard deviation of b and expand range about b based
+       on that. */
+    sb = sqrt(s2 * W/V);
+    incr = MAX(sb, tol);
+  
+    do {
+      incr *= 2.0;
+
+      /* Give up if the interval is too large */
+      if (incr > 100.0)
+        return 0;
+
+      blo = b - incr;
+      bhi = b + incr;
+
+      /* We don't want 'a' yet */
+      eval_robust_residual(x + start, y + start, n_points, blo, &a, &rlo);
+      eval_robust_residual(x + start, y + start, n_points, bhi, &a, &rhi);
+
+    } while (rlo * rhi >= 0.0); /* fn vals have same sign or one is zero,
+                                   i.e. root not in interval (rlo, rhi). */
+
+    /* OK, so the root for b lies in (blo, bhi). Start bisecting */
+    do {
+      bmid = 0.5 * (blo + bhi);
+      if (!(blo < bmid && bmid < bhi))
+        break;
+      eval_robust_residual(x + start, y + start, n_points, bmid, &a, &rmid);
+      if (rmid == 0.0) {
+        break;
+      } else if (rmid * rlo > 0.0) {
+        blo = bmid;
+        rlo = rmid;
+      } else if (rmid * rhi > 0.0) {
+        bhi = bmid;
+        rhi = rmid;
+      } else {
+        assert(0);
+      }
+    } while (bhi - blo > tol);
+
+    *b0 = a;
+    *b1 = bmid;
+
+    /* Number of runs test, but not if we're already down to the
+       minimum number of points */
+    if (n_points == MIN_SAMPLES_FOR_REGRESS) {
+      break;
+    }
+
+    for (i=start; i<n; i++) {
+      resids[i] = y[i] - a - bmid * x[i];
+    }
+
+    nruns = n_runs_from_residuals(resids + start, n_points);
+
+    if (nruns > critical_runs[n_points]) {
+      break;
+    } else {
+      start++;
+    }
+
+  } while (1);
+
+  *n_runs = nruns;
+  *best_start = start;
+
+  return 1;
+
+}
+
+/* ================================================== */
+/* This routine performs linear regression with two independent variables.
+   It returns non-zero status if there were enough data points and there
+   was a solution. */
+
+int
+RGR_MultipleRegress
+(double *x1,                    /* first independent variable */
+ double *x2,                    /* second independent variable */
+ double *y,                     /* measured data */
+
+ int n,                         /* number of data points */
+
+ /* The results */
+ double *b2                     /* estimated second slope */
+                                /* other values are not needed yet */
+)
+{
+  double Sx1, Sx2, Sx1x1, Sx1x2, Sx2x2, Sx1y, Sx2y, Sy;
+  double U, V, V1, V2, V3;
+  int i;
+
+  if (n < 4)
+    return 0;
+
+  Sx1 = Sx2 = Sx1x1 = Sx1x2 = Sx2x2 = Sx1y = Sx2y = Sy = 0.0;
+
+  for (i = 0; i < n; i++) {
+    Sx1 += x1[i];
+    Sx2 += x2[i];
+    Sx1x1 += x1[i] * x1[i];
+    Sx1x2 += x1[i] * x2[i];
+    Sx2x2 += x2[i] * x2[i];
+    Sx1y += x1[i] * y[i];
+    Sx2y += x2[i] * y[i];
+    Sy += y[i];
+  }
+
+  U = n * (Sx1x2 * Sx1y - Sx1x1 * Sx2y) +
+      Sx1 * Sx1 * Sx2y - Sx1 * Sx2 * Sx1y +
+      Sy * (Sx2 * Sx1x1 - Sx1 * Sx1x2);
+
+  V1 = n * (Sx1x2 * Sx1x2 - Sx1x1 * Sx2x2);
+  V2 = Sx1 * Sx1 * Sx2x2 + Sx2 * Sx2 * Sx1x1;
+  V3 = -2.0 * Sx1 * Sx2 * Sx1x2;
+  V = V1 + V2 + V3;
+
+  /* Check if there is a (numerically stable) solution */
+  if (fabs(V) * 1.0e10 <= -V1 + V2 + fabs(V3))
+    return 0;
+
+  *b2 = U / V;
+
+  return 1;
+}
diff --git a/chrony_3_3/regress.h b/chrony_3_3/regress.h
new file mode 100644
index 0000000..90055da
--- /dev/null
+++ b/chrony_3_3/regress.h
@@ -0,0 +1,137 @@
+/*
+  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 regression routine(s)
+
+  */
+
+#ifndef GOT_REGRESS_H
+#define GOT_REGRESS_H
+
+extern void
+RGR_WeightedRegression
+(double *x,                     /* independent variable */
+ double *y,                     /* measured data */
+ double *w,                     /* weightings (large => data
+                                   less reliable) */
+ 
+ int n,                         /* number of data points */
+
+ /* And now the results */
+
+ double *b0,                    /* estimated y axis intercept */
+ double *b1,                    /* estimated slope */
+ double *s2,                    /* estimated variance (weighted) of
+                                   data points */
+ 
+ double *sb0,                   /* estimated standard deviation of
+                                   intercept */
+ double *sb1                    /* estimated standard deviation of
+                                   slope */
+
+ /* Could add correlation stuff later if required */
+);
+
+/* Return the weighting to apply to the standard deviation to get a
+   given size of confidence interval assuming a T distribution */
+
+extern double RGR_GetTCoef(int dof);
+
+/* Return the value to apply to the variance to make an upper one-sided
+   test assuming a chi-square distribution. */
+
+extern double RGR_GetChi2Coef(int dof);
+
+/* Maximum ratio of number of points used for runs test to number of regression
+   points */
+#define REGRESS_RUNS_RATIO 2
+
+/* Minimum number of samples for regression */
+#define MIN_SAMPLES_FOR_REGRESS 3
+
+/* Return a status indicating whether there were enough points to
+   carry out the regression */
+
+extern int
+RGR_FindBestRegression 
+(double *x,                     /* independent variable */
+ double *y,                     /* measured data */
+ double *w,                     /* weightings (large => data
+                                   less reliable) */
+ 
+ int n,                         /* number of data points */
+ int m,                         /* number of extra samples in x and y arrays
+                                   (negative index) which can be used to
+                                   extend runs test */
+ int min_samples,               /* minimum number of samples to be kept after
+                                   changing the starting index to pass the runs
+                                   test */
+
+ /* And now the results */
+
+ double *b0,                    /* estimated y axis intercept */
+ double *b1,                    /* estimated slope */
+ double *s2,                    /* estimated variance of data points */
+ 
+ double *sb0,                   /* estimated standard deviation of
+                                   intercept */
+ double *sb1,                   /* estimated standard deviation of
+                                   slope */
+
+ int *new_start,                /* the new starting index to make the
+                                   residuals pass the two tests */
+
+ int *n_runs,                   /* number of runs amongst the residuals */
+
+ int *dof                       /* degrees of freedom in statistics (needed
+                                   to get confidence intervals later) */
+
+);
+
+int
+RGR_FindBestRobustRegression
+(double *x,
+ double *y,
+ int n,
+ double tol,
+ double *b0,
+ double *b1,
+ int *n_runs,
+ int *best_start);
+
+int
+RGR_MultipleRegress
+(double *x1,                    /* first independent variable */
+ double *x2,                    /* second independent variable */
+ double *y,                     /* measured data */
+
+ int n,                         /* number of data points */
+
+ /* The results */
+ double *b2                     /* estimated second slope */
+);
+
+/* Return the median value from an array */
+extern double RGR_FindMedian(double *x, int n);
+
+#endif /* GOT_REGRESS_H */
diff --git a/chrony_3_3/reports.h b/chrony_3_3/reports.h
new file mode 100644
index 0000000..6a24670
--- /dev/null
+++ b/chrony_3_3/reports.h
@@ -0,0 +1,163 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Data structure definitions within the daemon for various reports that
+  can be generated */
+
+#ifndef GOT_REPORTS_H
+#define GOT_REPORTS_H
+
+#include "sysincl.h"
+#include "addressing.h"
+#include "ntp.h"
+
+typedef struct {
+  IPAddr ip_addr;
+  int stratum;
+  int poll;
+  enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode;
+  enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE, RPT_OUTLIER} state;
+  int sel_options;
+
+  int reachability;
+  unsigned long latest_meas_ago; /* seconds */
+  double orig_latest_meas; /* seconds */
+  double latest_meas; /* seconds */
+  double latest_meas_err; /* seconds */
+} RPT_SourceReport ;
+
+typedef struct {
+  uint32_t ref_id;
+  IPAddr ip_addr;
+  int stratum;
+  NTP_Leap leap_status;
+  struct timespec ref_time;
+  double current_correction;
+  double last_offset;
+  double rms_offset;
+  double freq_ppm;
+  double resid_freq_ppm;
+  double skew_ppm;
+  double root_delay;
+  double root_dispersion;
+  double last_update_interval;
+} RPT_TrackingReport;
+
+typedef struct {
+  uint32_t ref_id;
+  IPAddr ip_addr;
+  unsigned long n_samples;
+  unsigned long n_runs;
+  unsigned long span_seconds;
+  double resid_freq_ppm;
+  double skew_ppm;
+  double sd;
+  double est_offset;
+  double est_offset_err;
+} RPT_SourcestatsReport;
+
+typedef struct {
+  struct timespec ref_time;
+  unsigned short n_samples;
+  unsigned short n_runs;
+  unsigned long span_seconds;
+  double rtc_seconds_fast;
+  double rtc_gain_rate_ppm;
+} RPT_RTC_Report;
+
+typedef struct {
+  IPAddr ip_addr;
+  uint32_t ntp_hits;
+  uint32_t cmd_hits;
+  uint16_t ntp_drops;
+  uint16_t cmd_drops;
+  int8_t ntp_interval;
+  int8_t cmd_interval;
+  int8_t ntp_timeout_interval;
+  uint32_t last_ntp_hit_ago;
+  uint32_t last_cmd_hit_ago;
+} RPT_ClientAccessByIndex_Report;
+
+typedef struct {
+  uint32_t ntp_hits;
+  uint32_t cmd_hits;
+  uint32_t ntp_drops;
+  uint32_t cmd_drops;
+  uint32_t log_drops;
+} RPT_ServerStatsReport;
+
+typedef struct {
+  struct timespec when;
+  double slewed_offset;
+  double orig_offset;
+  double residual;
+} RPT_ManualSamplesReport;
+
+typedef struct {
+  int online;
+  int offline;
+  int burst_online;
+  int burst_offline;
+  int unresolved;
+} RPT_ActivityReport;
+
+typedef struct {
+  int active;
+  int leap_only;
+  double offset;
+  double freq_ppm;
+  double wander_ppm;
+  double last_update_ago;
+  double remaining_time;
+} RPT_SmoothingReport;
+
+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;
+  double root_delay;
+  double root_dispersion;
+  uint32_t ref_id;
+  struct timespec ref_time;
+  double offset;
+  double peer_delay;
+  double peer_dispersion;
+  double response_time;
+  double jitter_asymmetry;
+  uint16_t tests;
+  int interleaved;
+  int authenticated;
+  char tx_tss_char;
+  char rx_tss_char;
+  uint32_t total_tx_count;
+  uint32_t total_rx_count;
+  uint32_t total_valid_count;
+} RPT_NTPReport;
+
+#endif /* GOT_REPORTS_H */
diff --git a/chrony_3_3/rtc.c b/chrony_3_3/rtc.c
new file mode 100644
index 0000000..33d04bf
--- /dev/null
+++ b/chrony_3_3/rtc.c
@@ -0,0 +1,240 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "rtc.h"
+#include "local.h"
+#include "logging.h"
+#include "conf.h"
+
+#if defined LINUX && defined FEAT_RTC
+#include "rtc_linux.h"
+#endif /* defined LINUX */
+
+/* ================================================== */
+
+static int driver_initialised = 0;
+static int driver_preinit_ok = 0;
+
+static struct {
+  int  (*init)(void);
+  void (*fini)(void);
+  int  (*time_pre_init)(time_t driftfile_time);
+  void (*time_init)(void (*after_hook)(void*), void *anything);
+  void (*start_measurements)(void);
+  int  (*write_parameters)(void);
+  int  (*get_report)(RPT_RTC_Report *report);
+  int  (*trim)(void);
+} driver =
+{
+#if defined LINUX && defined FEAT_RTC
+  RTC_Linux_Initialise,
+  RTC_Linux_Finalise,
+  RTC_Linux_TimePreInit,
+  RTC_Linux_TimeInit,
+  RTC_Linux_StartMeasurements,
+  RTC_Linux_WriteParameters,
+  RTC_Linux_GetReport,
+  RTC_Linux_Trim
+#else
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+#endif 
+};
+     
+/* ================================================== */
+/* Get the last modification time of the driftfile */
+
+static time_t
+get_driftfile_time(void)
+{
+  struct stat buf;
+  char *drift_file;
+
+  drift_file = CNF_GetDriftFile();
+  if (!drift_file)
+    return 0;
+
+  if (stat(drift_file, &buf))
+    return 0;
+
+  return buf.st_mtime;
+}
+
+/* ================================================== */
+/* Set the system time to the driftfile time if it's in the future */
+
+static void
+apply_driftfile_time(time_t t)
+{
+  struct timespec now;
+
+  LCL_ReadCookedTime(&now, NULL);
+
+  if (now.tv_sec < t) {
+    if (LCL_ApplyStepOffset(now.tv_sec - t))
+      LOG(LOGS_INFO, "System time restored from driftfile");
+  }
+}
+
+/* ================================================== */
+
+void
+RTC_Initialise(int initial_set)
+{
+  time_t driftfile_time;
+  char *file_name;
+
+  /* If the -s option was specified, try to do an initial read of the RTC and
+     set the system time to it.  Also, read the last modification time of the
+     driftfile (i.e. system time when chronyd was previously stopped) and set
+     the system time to it if it's in the future to bring the clock closer to
+     the true time when the RTC is broken (e.g. it has no battery), is missing,
+     or there is no RTC driver. */
+  if (initial_set) {
+    driftfile_time = get_driftfile_time();
+
+    if (driver.time_pre_init && driver.time_pre_init(driftfile_time)) {
+      driver_preinit_ok = 1;
+    } else {
+      driver_preinit_ok = 0;
+      if (driftfile_time)
+        apply_driftfile_time(driftfile_time);
+    }
+  }
+
+  driver_initialised = 0;
+
+  /* This is how we tell whether the user wants to load the RTC
+     driver, if he is on a machine where it is an option. */
+  file_name = CNF_GetRtcFile();
+
+  if (file_name) {
+    if (CNF_GetRtcSync()) {
+      LOG_FATAL("rtcfile directive cannot be used with rtcsync");
+    }
+
+    if (driver.init) {
+      if ((driver.init)()) {
+        driver_initialised = 1;
+      }
+    } else {
+      LOG(LOGS_ERR, "RTC not supported on this operating system");
+    }
+  }
+}
+
+/* ================================================== */
+
+void
+RTC_Finalise(void)
+{
+  if (driver.fini) {
+    (driver.fini)();
+  }
+}
+
+/* ================================================== */
+/* Start the processing to get a single measurement from the real time
+   clock, and use it to trim the system time, based on knowing the
+   drift rate of the RTC and the error the last time we set it.  If the
+   TimePreInit routine has succeeded, we can be sure that the trim required
+   is not *too* large.
+
+   We are called with a hook to a function to be called after the
+   initialisation is complete.  We also call this if we cannot do the
+   initialisation. */
+
+void
+RTC_TimeInit(void (*after_hook)(void *), void *anything)
+{
+  if (driver_initialised && driver_preinit_ok) {
+    (driver.time_init)(after_hook, anything);
+  } else {
+    (after_hook)(anything);
+  }
+}
+
+/* ================================================== */
+/* Start the RTC measurement process */
+
+void
+RTC_StartMeasurements(void)
+{
+  if (driver_initialised) {
+    (driver.start_measurements)();
+  }
+  /* Benign if driver not present */
+}
+
+/* ================================================== */
+/* Write RTC information out to RTC file.  Return 0 for success, 1 if
+   RTC driver not running, or 2 if the file cannot be written. */
+
+int
+RTC_WriteParameters(void)
+{
+  if (driver_initialised) {
+    return (driver.write_parameters)();
+  } else {
+    return RTC_ST_NODRV;
+  }
+}
+
+/* ================================================== */
+
+int
+RTC_GetReport(RPT_RTC_Report *report)
+{
+  if (driver_initialised) {
+    return (driver.get_report)(report);
+  } else {
+    return 0;
+  }
+}
+
+/* ================================================== */
+
+int
+RTC_Trim(void)
+{
+  if (driver_initialised) {
+    return (driver.trim)();
+  } else {
+    return 0;
+  }
+}
+
+/* ================================================== */
+
diff --git a/chrony_3_3/rtc.h b/chrony_3_3/rtc.h
new file mode 100644
index 0000000..8fd677b
--- /dev/null
+++ b/chrony_3_3/rtc.h
@@ -0,0 +1,45 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  */
+
+#ifndef GOT_RTC_H
+#define GOT_RTC_H
+
+#include "reports.h"
+
+extern void RTC_Initialise(int initial_set);
+extern void RTC_Finalise(void);
+extern void RTC_TimeInit(void (*after_hook)(void *), void *anything);
+extern void RTC_StartMeasurements(void);
+extern int  RTC_GetReport(RPT_RTC_Report *report);
+
+#define RTC_ST_OK 0
+#define RTC_ST_NODRV 1
+#define RTC_ST_BADFILE 2
+
+extern int RTC_WriteParameters(void);
+
+extern int RTC_Trim(void);
+
+#endif /* GOT_RTC_H */
diff --git a/chrony_3_3/rtc_linux.c b/chrony_3_3/rtc_linux.c
new file mode 100644
index 0000000..89855c2
--- /dev/null
+++ b/chrony_3_3/rtc_linux.c
@@ -0,0 +1,1127 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2012-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Real-time clock driver for linux.  This interfaces the program with
+  the clock that keeps time when the machine is turned off.
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include <linux/rtc.h>
+
+#include "logging.h"
+#include "sched.h"
+#include "local.h"
+#include "util.h"
+#include "sys_linux.h"
+#include "reference.h"
+#include "regress.h"
+#include "rtc.h"
+#include "rtc_linux.h"
+#include "conf.h"
+#include "memory.h"
+
+/* ================================================== */
+/* Forward prototypes */
+
+static void measurement_timeout(void *any);
+
+static void read_from_device(int fd_, int event, void *any);
+
+/* ================================================== */
+
+typedef enum {
+  OM_NORMAL,
+  OM_INITIAL,
+  OM_AFTERTRIM
+} OperatingMode;
+
+static OperatingMode operating_mode = OM_NORMAL;
+
+/* ================================================== */
+
+static int fd = -1;
+
+#define LOWEST_MEASUREMENT_PERIOD 15
+#define HIGHEST_MEASUREMENT_PERIOD 480
+#define N_SAMPLES_PER_REGRESSION 1
+
+static int measurement_period = LOWEST_MEASUREMENT_PERIOD;
+
+static SCH_TimeoutID timeout_id = 0;
+
+static int skip_interrupts;
+
+/* ================================================== */
+
+/* Maximum number of samples held */
+#define MAX_SAMPLES 64
+
+/* Real time clock samples.  We store the seconds count as originally
+   measured, together with a 'trim' that compensates these values for
+   any steps made to the RTC to bring it back into line
+   occasionally.  The trim is in seconds. */
+static time_t *rtc_sec = NULL;
+static double *rtc_trim = NULL;
+
+/* Reference time, against which delta times on the RTC scale are measured */
+static time_t rtc_ref;
+
+
+/* System clock samples associated with the above samples. */
+static struct timespec *system_times = NULL;
+
+/* Number of samples currently stored. */
+static int n_samples;   
+
+/* Number of new samples since last regression */
+static int n_samples_since_regression;
+
+/* Number of runs of residuals in last regression (for logging) */
+static int n_runs;
+
+/* Coefficients */
+/* Whether they are valid */
+static int coefs_valid;
+
+/* Reference time */
+static time_t coef_ref_time;
+/* Number of seconds by which RTC was fast of the system time at coef_ref_time */
+static double coef_seconds_fast;
+
+/* Estimated number of seconds that RTC gains relative to system time
+   for each second of ITS OWN time */
+static double coef_gain_rate;
+
+/* Gain rate saved just before we step the RTC to correct it to the
+   nearest second, so that we can write a useful set of coefs to the
+   RTC data file once we have reacquired its offset after the step */
+static double saved_coef_gain_rate;
+
+/* Threshold for automatic RTC trimming in seconds, zero when disabled */
+static double autotrim_threshold;
+
+/* Filename supplied by config file where RTC coefficients are
+   stored. */
+static char *coefs_file_name;
+
+/* ================================================== */
+/* Coefficients read from file at start of run. */
+
+/* Whether we have tried to load the coefficients */
+static int tried_to_load_coefs = 0;
+
+/* Whether valid coefficients were read */
+static int valid_coefs_from_file = 0;
+
+/* Coefs read in */
+static time_t file_ref_time;
+static double file_ref_offset, file_rate_ppm;
+
+/* ================================================== */
+
+/* Flag to remember whether to assume the RTC is running on UTC */
+static int rtc_on_utc = 1;
+
+/* ================================================== */
+
+static LOG_FileID logfileid;
+
+/* ================================================== */
+
+static void (*after_init_hook)(void *) = NULL;
+static void *after_init_hook_arg = NULL;
+
+/* ================================================== */
+
+static void
+discard_samples(int new_first)
+{
+  int n_to_save;
+
+  assert(new_first >= 0 && new_first < n_samples);
+
+  n_to_save = n_samples - new_first;
+
+  memmove(rtc_sec, rtc_sec + new_first, n_to_save * sizeof(time_t));
+  memmove(rtc_trim, rtc_trim + new_first, n_to_save * sizeof(double));
+  memmove(system_times, system_times + new_first, n_to_save * sizeof(struct timespec));
+
+  n_samples = n_to_save;
+}
+
+/* ================================================== */
+
+#define NEW_FIRST_WHEN_FULL 4
+
+static void
+accumulate_sample(time_t rtc, struct timespec *sys)
+{
+
+  if (n_samples == MAX_SAMPLES) {
+    /* Discard oldest samples */
+    discard_samples(NEW_FIRST_WHEN_FULL);
+  }
+
+  /* Discard all samples if the RTC was stepped back (not our trim) */
+  if (n_samples > 0 && rtc_sec[n_samples - 1] - rtc >= rtc_trim[n_samples - 1]) {
+    DEBUG_LOG("RTC samples discarded");
+    n_samples = 0;
+  }
+
+  /* Always use most recent sample as reference */
+  /* use sample only if n_sample is not negative*/
+  if(n_samples >=0)
+  {
+  rtc_ref = rtc;
+  rtc_sec[n_samples] = rtc;
+  rtc_trim[n_samples] = 0.0;
+  system_times[n_samples] = *sys;
+  ++n_samples_since_regression;
+  }
+  ++n_samples;
+}
+
+/* ================================================== */
+/* The new_sample flag is to indicate whether to adjust the
+   measurement period depending on the behaviour of the standard
+   deviation. */
+
+static void
+run_regression(int new_sample,
+               int *valid,
+               time_t *ref,
+               double *fast,
+               double *slope)
+{
+  double rtc_rel[MAX_SAMPLES]; /* Relative times on RTC axis */
+  double offsets[MAX_SAMPLES]; /* How much the RTC is fast of the system clock */
+  int i;
+  double est_intercept, est_slope;
+  int best_new_start;
+
+  if (n_samples > 0) {
+
+    for (i=0; i<n_samples; i++) {
+      rtc_rel[i] = rtc_trim[i] + (double)(rtc_sec[i] - rtc_ref);
+      offsets[i] = ((double) (rtc_ref - system_times[i].tv_sec) -
+                    (1.0e-9 * system_times[i].tv_nsec) +
+                    rtc_rel[i]);
+
+    }
+
+    if (RGR_FindBestRobustRegression
+        (rtc_rel, offsets,
+         n_samples, 1.0e-9,
+         &est_intercept, &est_slope,
+         &n_runs,
+         &best_new_start)) {
+
+      /* Calculate and store coefficients.  We don't do any error
+         bounds processing on any of these. */
+      *valid = 1;
+      *ref = rtc_ref;
+      *fast = est_intercept;
+      *slope = est_slope;
+
+      if (best_new_start > 0) {
+        discard_samples(best_new_start);
+      }
+
+
+    } else {
+      /* Keep existing coefficients. */
+    }
+  } else {
+    /* Keep existing coefficients. */
+  }
+
+}
+
+/* ================================================== */
+
+static void
+slew_samples
+(struct timespec *raw, struct timespec *cooked,
+ double dfreq,
+ double doffset,
+ LCL_ChangeType change_type,
+ void *anything)
+{
+  int i;
+  double delta_time;
+  double old_seconds_fast, old_gain_rate;
+
+  if (change_type == LCL_ChangeUnknownStep) {
+    /* Drop all samples. */
+    n_samples = 0;
+  }
+
+  for (i=0; i<n_samples; i++) {
+    UTI_AdjustTimespec(system_times + i, cooked, system_times + i, &delta_time,
+        dfreq, doffset);
+  }
+
+  old_seconds_fast = coef_seconds_fast;
+  old_gain_rate = coef_gain_rate;
+
+  if (coefs_valid) {
+    coef_seconds_fast += doffset;
+    coef_gain_rate += dfreq * (1.0 - coef_gain_rate);
+  }
+
+  DEBUG_LOG("dfreq=%.8f doffset=%.6f old_fast=%.6f old_rate=%.3f new_fast=%.6f new_rate=%.3f",
+      dfreq, doffset,
+      old_seconds_fast, 1.0e6 * old_gain_rate,
+      coef_seconds_fast, 1.0e6 * coef_gain_rate);
+}
+
+/* ================================================== */
+
+/* Function to convert from a time_t value represenging UTC to the
+   corresponding real time clock 'DMY HMS' form, taking account of
+   whether the user runs his RTC on the local time zone or UTC */
+
+static struct tm *
+rtc_from_t(const time_t *t)
+{
+  if (rtc_on_utc) {
+    return gmtime(t);
+  } else {
+    return localtime(t);
+  }
+}
+
+/* ================================================== */
+
+/* Inverse function to get back from RTC 'DMY HMS' form to time_t UTC
+   form.  This essentially uses mktime(), but involves some awful
+   complexity to cope with timezones.  The problem is that mktime's
+   behaviour with regard to the daylight saving flag in the 'struct
+   tm' does not seem to be reliable across all systems, unless that
+   flag is set to zero. 
+
+   tm_isdst = -1 does not seem to work with all libc's - it is treated
+   as meaning there is DST, or fails completely.  (It is supposed to
+   use the timezone info to work out whether summer time is active at
+   the specified epoch).
+
+   tm_isdst = 1 fails if the local timezone has no summer time defined.
+
+   The approach taken is as follows.  Suppose the RTC is on localtime.
+   We perform all mktime calls with the tm_isdst field set to zero.
+
+   Let y be the RTC reading in 'DMY HMS' form.  Let M be the mktime
+   function with tm_isdst=0 and L be the localtime function.
+
+   We seek x such that y = L(x).  Now there will exist a value Z(t)
+   such that M(L(t)) = t + Z(t) for all t, where Z(t) depends on
+   whether daylight saving is active at time t.
+
+   We want L(x) = y.  Therefore M(L(x)) = x + Z = M(y).  But
+   M(L(M(y))) = M(y) + Z.  Therefore x = M(y) - Z = M(y) - (M(L(M(y)))
+   - M(y)).
+
+   The case for the RTC running on UTC is identical but without the
+   potential complication that Z depends on t.
+*/
+
+static time_t
+t_from_rtc(struct tm *stm) {
+  struct tm temp1, temp2;
+  long diff;
+  time_t t1, t2;
+
+  temp1 = *stm;
+  temp1.tm_isdst = 0;
+  
+  t1 = mktime(&temp1);
+  if (rtc_on_utc) {
+    temp2 = *gmtime(&t1);
+  } else {
+    temp2 = *localtime(&t1);
+  }
+  
+  temp2.tm_isdst = 0;
+  t2 = mktime(&temp2);
+  diff = t2 - t1;
+
+  if (t1 - diff == -1)
+    DEBUG_LOG("Could not convert RTC time");
+
+  return t1 - diff;
+}
+
+/* ================================================== */
+
+static void
+read_hwclock_file(const char *hwclock_file)
+{
+  FILE *in;
+  char line[256];
+  int i;
+
+  if (!hwclock_file || !hwclock_file[0])
+    return;
+
+  in = fopen(hwclock_file, "r");
+  if (!in) {
+    LOG(LOGS_WARN, "Could not open %s : %s",
+        hwclock_file, strerror(errno));
+    return;
+  }
+
+  /* Read third line from the file. */
+  for (i = 0; i < 3; i++) {
+    if (!fgets(line, sizeof(line), in))
+      break;
+  }
+
+  fclose(in);
+
+  if (i == 3 && !strncmp(line, "LOCAL", 5)) {
+    rtc_on_utc = 0;
+  } else if (i == 3 && !strncmp(line, "UTC", 3)) {
+    rtc_on_utc = 1;
+  } else {
+    LOG(LOGS_WARN, "Could not read RTC LOCAL/UTC setting from %s", hwclock_file);
+  }
+}
+
+/* ================================================== */
+
+static void
+setup_config(void)
+{
+  if (CNF_GetRtcOnUtc()) {
+    rtc_on_utc = 1;
+  } else {
+    rtc_on_utc = 0;
+  }
+
+  read_hwclock_file(CNF_GetHwclockFile());
+
+  autotrim_threshold = CNF_GetRtcAutotrim();
+}
+
+/* ================================================== */
+/* Read the coefficients from the file where they were saved
+   the last time the program was run. */
+
+static void
+read_coefs_from_file(void)
+{
+  FILE *in;
+
+  if (!tried_to_load_coefs) {
+
+    valid_coefs_from_file = 0; /* only gets set true if we succeed */
+
+    tried_to_load_coefs = 1;
+
+    if (coefs_file_name && (in = fopen(coefs_file_name, "r"))) {
+      if (fscanf(in, "%d%ld%lf%lf",
+                 &valid_coefs_from_file,
+                 &file_ref_time,
+                 &file_ref_offset,
+                 &file_rate_ppm) == 4) {
+      } else {
+        LOG(LOGS_WARN, "Could not read coefficients from %s", coefs_file_name);
+      }
+      fclose(in);
+    }
+  }
+}
+
+/* ================================================== */
+/* Write the coefficients to the file where they will be read
+   the next time the program is run. */
+
+static int
+write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
+{
+  struct stat buf;
+  char *temp_coefs_file_name;
+  FILE *out;
+  int r1, r2;
+
+  /* Create a temporary file with a '.tmp' extension. */
+
+  temp_coefs_file_name = (char*) Malloc(strlen(coefs_file_name)+8);
+
+  if(!temp_coefs_file_name) {
+    return RTC_ST_BADFILE;
+  }
+
+  strcpy(temp_coefs_file_name,coefs_file_name);
+  strcat(temp_coefs_file_name,".tmp");
+
+  out = fopen(temp_coefs_file_name, "w");
+  if (!out) {
+    Free(temp_coefs_file_name);
+    LOG(LOGS_WARN, "Could not open temporary RTC file %s.tmp for writing",
+        coefs_file_name);
+    return RTC_ST_BADFILE;
+  }
+
+  /* Gain rate is written out in ppm */
+  r1 = fprintf(out, "%1d %ld %.6f %.3f\n",
+               valid, ref_time, offset, 1.0e6 * rate);
+  r2 = fclose(out);
+  if (r1 < 0 || r2) {
+    Free(temp_coefs_file_name);
+    LOG(LOGS_WARN, "Could not write to temporary RTC file %s.tmp",
+        coefs_file_name);
+    return RTC_ST_BADFILE;
+  }
+
+  /* Clone the file attributes from the existing file if there is one. */
+
+  if (!stat(coefs_file_name,&buf)) {
+    if (chown(temp_coefs_file_name,buf.st_uid,buf.st_gid) ||
+        chmod(temp_coefs_file_name,buf.st_mode & 0777)) {
+      LOG(LOGS_WARN,
+          "Could not change ownership or permissions of temporary RTC file %s.tmp",
+          coefs_file_name);
+    }
+  }
+
+  /* Rename the temporary file to the correct location (see rename(2) for details). */
+
+  if (rename(temp_coefs_file_name,coefs_file_name)) {
+    unlink(temp_coefs_file_name);
+    Free(temp_coefs_file_name);
+    LOG(LOGS_WARN, "Could not replace old RTC file %s.tmp with new one %s",
+        coefs_file_name, coefs_file_name);
+    return RTC_ST_BADFILE;
+  }
+
+  Free(temp_coefs_file_name);
+
+  return RTC_ST_OK;
+}
+
+
+/* ================================================== */
+/* file_name is the name of the file where we save the RTC params
+   between executions.  Return status is whether we could initialise
+   on this version of the system. */
+
+int
+RTC_Linux_Initialise(void)
+{
+  rtc_sec = MallocArray(time_t, MAX_SAMPLES);
+  rtc_trim = MallocArray(double, MAX_SAMPLES);
+  system_times = MallocArray(struct timespec, MAX_SAMPLES);
+
+  /* Setup details depending on configuration options */
+  setup_config();
+
+  /* In case it didn't get done by pre-init */
+  coefs_file_name = CNF_GetRtcFile();
+
+  /* Try to open device */
+
+  fd = open (CNF_GetRtcDevice(), O_RDWR);
+  if (fd < 0) {
+    LOG(LOGS_ERR, "Could not open RTC device %s : %s",
+        CNF_GetRtcDevice(), strerror(errno));
+    return 0;
+  }
+
+  /* Close on exec */
+  UTI_FdSetCloexec(fd);
+
+  n_samples = 0;
+  n_samples_since_regression = 0;
+  n_runs = 0;
+  coefs_valid = 0;
+
+  measurement_period = LOWEST_MEASUREMENT_PERIOD;
+
+  operating_mode = OM_NORMAL;
+
+  /* Register file handler */
+  SCH_AddFileHandler(fd, SCH_FILE_INPUT, read_from_device, NULL);
+
+  /* Register slew handler */
+  LCL_AddParameterChangeHandler(slew_samples, NULL);
+
+  logfileid = CNF_GetLogRtc() ? LOG_FileOpen("rtc",
+      "   Date (UTC) Time   RTC fast (s) Val   Est fast (s)   Slope (ppm)  Ns  Nr Meas")
+    : -1;
+  return 1;
+}
+
+/* ================================================== */
+
+void
+RTC_Linux_Finalise(void)
+{
+  SCH_RemoveTimeout(timeout_id);
+  timeout_id = 0;
+
+  /* Remove input file handler */
+  if (fd >= 0) {
+    SCH_RemoveFileHandler(fd);
+    close(fd);
+
+    /* Save the RTC data */
+    (void) RTC_Linux_WriteParameters();
+
+  }
+  Free(rtc_sec);
+  Free(rtc_trim);
+  Free(system_times);
+}
+
+/* ================================================== */
+
+static void
+switch_interrupts(int onoff)
+{
+  int status;
+
+  if (onoff) {
+    status = ioctl(fd, RTC_UIE_ON, 0);
+    if (status < 0) {
+      LOG(LOGS_ERR, "Could not %s RTC interrupt : %s", "enable", strerror(errno));
+      return;
+    }
+    skip_interrupts = 1;
+  } else {
+    status = ioctl(fd, RTC_UIE_OFF, 0);
+    if (status < 0) {
+      LOG(LOGS_ERR, "Could not %s RTC interrupt : %s", "disable", strerror(errno));
+      return;
+    }
+  }
+}    
+
+/* ================================================== */
+
+static void
+measurement_timeout(void *any)
+{
+  timeout_id = 0;
+  switch_interrupts(1);
+}
+
+/* ================================================== */
+
+static void
+set_rtc(time_t new_rtc_time)
+{
+  struct tm rtc_tm;
+  struct rtc_time rtc_raw;
+  int status;
+
+  rtc_tm = *rtc_from_t(&new_rtc_time);
+
+  rtc_raw.tm_sec = rtc_tm.tm_sec;
+  rtc_raw.tm_min = rtc_tm.tm_min;
+  rtc_raw.tm_hour = rtc_tm.tm_hour;
+  rtc_raw.tm_mday = rtc_tm.tm_mday;
+  rtc_raw.tm_mon = rtc_tm.tm_mon;
+  rtc_raw.tm_year = rtc_tm.tm_year;
+  rtc_raw.tm_wday = rtc_tm.tm_wday;
+  rtc_raw.tm_yday = rtc_tm.tm_yday;
+  rtc_raw.tm_isdst = rtc_tm.tm_isdst;
+
+  status = ioctl(fd, RTC_SET_TIME, &rtc_raw);
+  if (status < 0) {
+    LOG(LOGS_ERR, "Could not set RTC time");
+  }
+
+}
+
+/* ================================================== */
+
+static void
+handle_initial_trim(void)
+{
+  double rate;
+  long delta_time;
+  double rtc_error_now, sys_error_now;
+
+    /* The idea is to accumulate some number of samples at 1 second
+       intervals, then do a robust regression fit to this.  This
+       should give a good fix on the intercept (=system clock error
+       rel to RTC) at a particular time, removing risk of any
+       particular sample being an outlier.  We can then look at the
+       elapsed interval since the epoch recorded in the RTC file,
+       and correct the system time accordingly. */
+    
+  run_regression(1, &coefs_valid, &coef_ref_time, &coef_seconds_fast, &coef_gain_rate);
+
+  n_samples_since_regression = 0;
+
+  /* Set sample number to -1 so the next sample is not used, as it will not yet be corrected for System Trim*/
+
+  n_samples = -1;
+
+
+  read_coefs_from_file();
+
+  if (valid_coefs_from_file) {
+    /* Can process data */
+    delta_time = coef_ref_time - file_ref_time;
+    rate = 1.0e-6 * file_rate_ppm;
+    rtc_error_now = file_ref_offset + rate * (double) delta_time;
+          
+    /* sys_error_now is positive if the system clock is fast */
+    sys_error_now = rtc_error_now - coef_seconds_fast;
+          
+    LCL_AccumulateOffset(sys_error_now, 0.0);
+    LOG(LOGS_INFO, "System clock off from RTC by %f seconds (slew)",
+        sys_error_now);
+  } else {
+    LOG(LOGS_WARN, "No valid rtcfile coefficients");
+  }
+  
+  coefs_valid = 0;
+  
+  (after_init_hook)(after_init_hook_arg);
+  
+  operating_mode = OM_NORMAL;
+}
+
+/* ================================================== */
+
+static void
+handle_relock_after_trim(void)
+{
+  int valid;
+  time_t ref;
+  double fast, slope;
+
+  valid = 0;
+  run_regression(1, &valid, &ref, &fast, &slope);
+
+  if (valid) {
+    write_coefs_to_file(1,ref,fast,saved_coef_gain_rate);
+  } else {
+    DEBUG_LOG("Could not do regression after trim");
+  }
+
+  coefs_valid = 0;
+  n_samples = 0;
+  n_samples_since_regression = 0;
+  operating_mode = OM_NORMAL;
+  measurement_period = LOWEST_MEASUREMENT_PERIOD;
+}
+
+/* ================================================== */
+
+static void
+maybe_autotrim(void)
+{
+  /* Trim only when in normal mode, the coefficients are fresh, the current
+     offset is above the threshold and the system clock is synchronized */
+
+  if (operating_mode != OM_NORMAL || !coefs_valid || n_samples_since_regression)
+    return;
+  
+  if (autotrim_threshold <= 0.0 || fabs(coef_seconds_fast) < autotrim_threshold)
+    return;
+
+  if (REF_GetOurStratum() >= 16)
+    return;
+
+  RTC_Linux_Trim();
+}
+
+/* ================================================== */
+
+static void
+process_reading(time_t rtc_time, struct timespec *system_time)
+{
+  double rtc_fast;
+
+  accumulate_sample(rtc_time, system_time);
+
+  switch (operating_mode) {
+    case OM_NORMAL:
+
+      if (n_samples_since_regression >= N_SAMPLES_PER_REGRESSION) {
+        run_regression(1, &coefs_valid, &coef_ref_time, &coef_seconds_fast, &coef_gain_rate);
+        n_samples_since_regression = 0;
+        maybe_autotrim();
+      }
+      
+      break;
+    case OM_INITIAL:
+      if (n_samples_since_regression >= 8) {
+        handle_initial_trim();
+      }
+      break;
+    case OM_AFTERTRIM:
+      if (n_samples_since_regression >= 8) {
+        handle_relock_after_trim();
+      }
+      break;
+    default:
+      assert(0);
+      break;
+  }  
+
+
+  if (logfileid != -1) {
+    rtc_fast = (rtc_time - system_time->tv_sec) - 1.0e-9 * system_time->tv_nsec;
+
+    LOG_FileWrite(logfileid, "%s %14.6f %1d  %14.6f  %12.3f  %2d  %2d %4d",
+            UTI_TimeToLogForm(system_time->tv_sec),
+            rtc_fast,
+            coefs_valid,
+            coef_seconds_fast, coef_gain_rate * 1.0e6, n_samples, n_runs, measurement_period);
+  }    
+
+}
+
+/* ================================================== */
+
+static void
+read_from_device(int fd_, int event, void *any)
+{
+  int status;
+  unsigned long data;
+  struct timespec sys_time;
+  struct rtc_time rtc_raw;
+  struct tm rtc_tm;
+  time_t rtc_t;
+  int error = 0;
+
+  status = read(fd, &data, sizeof(data));
+
+  if (status < 0) {
+    /* This looks like a bad error : the file descriptor was indicating it was
+     * ready to read but we couldn't read anything.  Give up. */
+    LOG(LOGS_ERR, "Could not read flags %s : %s", CNF_GetRtcDevice(), strerror(errno));
+    SCH_RemoveFileHandler(fd);
+    switch_interrupts(0); /* Likely to raise error too, but just to be sure... */
+    close(fd);
+    fd = -1;
+    return;
+  }    
+
+  if (skip_interrupts > 0) {
+    /* Wait for the next interrupt, this one may be bogus */
+    skip_interrupts--;
+    return;
+  }
+
+  if ((data & RTC_UF) == RTC_UF) {
+    /* Update interrupt detected */
+    
+    /* Read RTC time, sandwiched between two polls of the system clock
+       so we can bound any error. */
+
+    SCH_GetLastEventTime(&sys_time, NULL, NULL);
+
+    status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
+    if (status < 0) {
+      LOG(LOGS_ERR, "Could not read time from %s : %s", CNF_GetRtcDevice(), strerror(errno));
+      error = 1;
+      goto turn_off_interrupt;
+    }
+
+    /* Convert RTC time into a struct timespec */
+    rtc_tm.tm_sec = rtc_raw.tm_sec;
+    rtc_tm.tm_min = rtc_raw.tm_min;
+    rtc_tm.tm_hour = rtc_raw.tm_hour;
+    rtc_tm.tm_mday = rtc_raw.tm_mday;
+    rtc_tm.tm_mon = rtc_raw.tm_mon;
+    rtc_tm.tm_year = rtc_raw.tm_year;
+
+    rtc_t = t_from_rtc(&rtc_tm);
+
+    if (rtc_t == (time_t)(-1)) {
+      error = 1;
+      goto turn_off_interrupt;
+    }      
+
+    process_reading(rtc_t, &sys_time);
+
+    if (n_samples < 4) {
+      measurement_period = LOWEST_MEASUREMENT_PERIOD;
+    } else if (n_samples < 6) {
+      measurement_period = LOWEST_MEASUREMENT_PERIOD << 1;
+    } else if (n_samples < 10) {
+      measurement_period = LOWEST_MEASUREMENT_PERIOD << 2;
+    } else if (n_samples < 14) {
+      measurement_period = LOWEST_MEASUREMENT_PERIOD << 3;
+    } else {
+      measurement_period = LOWEST_MEASUREMENT_PERIOD << 4;
+    }
+
+  }
+
+turn_off_interrupt:
+
+  switch (operating_mode) {
+    case OM_INITIAL:
+      if (error) {
+        DEBUG_LOG("Could not complete initial step due to errors");
+        operating_mode = OM_NORMAL;
+        (after_init_hook)(after_init_hook_arg);
+
+        switch_interrupts(0);
+    
+        timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
+      }
+
+      break;
+
+    case OM_AFTERTRIM:
+      if (error) {
+        DEBUG_LOG("Could not complete after trim relock due to errors");
+        operating_mode = OM_NORMAL;
+
+        switch_interrupts(0);
+    
+        timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
+      }
+      
+      break;
+
+    case OM_NORMAL:
+      switch_interrupts(0);
+    
+      timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
+
+      break;
+    default:
+      assert(0);
+      break;
+  }
+
+}
+
+/* ================================================== */
+
+void
+RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything)
+{
+  after_init_hook = after_hook;
+  after_init_hook_arg = anything;
+
+  operating_mode = OM_INITIAL;
+  timeout_id = 0;
+  switch_interrupts(1);
+}
+
+/* ================================================== */
+
+void
+RTC_Linux_StartMeasurements(void)
+{
+  measurement_timeout(NULL);
+}
+
+/* ================================================== */
+
+int
+RTC_Linux_WriteParameters(void)
+{
+  int retval;
+
+  if (fd < 0) {
+    return RTC_ST_NODRV;
+  }
+  
+  if (coefs_valid) {
+    retval = write_coefs_to_file(1,coef_ref_time, coef_seconds_fast, coef_gain_rate);
+  } else {
+   /* Don't change the existing file, it may not be 100% valid but is our
+      current best guess. */
+    retval = RTC_ST_OK; /*write_coefs_to_file(0,0,0.0,0.0); */
+  }
+
+  return(retval);
+}
+
+/* ================================================== */
+/* Try to set the system clock from the RTC, in the same manner as
+   /sbin/hwclock -s would do.  We're not as picky about OS version
+   etc in this case, since we have fewer requirements regarding the
+   RTC behaviour than we do for the rest of the module. */
+
+int
+RTC_Linux_TimePreInit(time_t driftfile_time)
+{
+  int fd, status;
+  struct rtc_time rtc_raw, rtc_raw_retry;
+  struct tm rtc_tm;
+  time_t rtc_t;
+  double accumulated_error, sys_offset;
+  struct timespec new_sys_time, old_sys_time;
+
+  coefs_file_name = CNF_GetRtcFile();
+
+  setup_config();
+  read_coefs_from_file();
+
+  fd = open(CNF_GetRtcDevice(), O_RDONLY);
+
+  if (fd < 0) {
+    return 0; /* Can't open it, and won't be able to later */
+  }
+
+  /* Retry reading the rtc until both read attempts give the same sec value.
+     This way the race condition is prevented that the RTC has updated itself
+     during the first read operation. */
+  do {
+    status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
+    if (status >= 0) {
+      status = ioctl(fd, RTC_RD_TIME, &rtc_raw_retry);
+    }
+  } while (status >= 0 && rtc_raw.tm_sec != rtc_raw_retry.tm_sec);
+
+  /* Read system clock */
+  LCL_ReadCookedTime(&old_sys_time, NULL);
+
+  close(fd);
+
+  if (status >= 0) {
+    /* Convert to seconds since 1970 */
+    rtc_tm.tm_sec = rtc_raw.tm_sec;
+    rtc_tm.tm_min = rtc_raw.tm_min;
+    rtc_tm.tm_hour = rtc_raw.tm_hour;
+    rtc_tm.tm_mday = rtc_raw.tm_mday;
+    rtc_tm.tm_mon = rtc_raw.tm_mon;
+    rtc_tm.tm_year = rtc_raw.tm_year;
+    
+    rtc_t = t_from_rtc(&rtc_tm);
+
+    if (rtc_t != (time_t)(-1)) {
+
+      /* Work out approximatation to correct time (to about the
+         nearest second) */
+      if (valid_coefs_from_file) {
+        accumulated_error = file_ref_offset +
+          (rtc_t - file_ref_time) * 1.0e-6 * file_rate_ppm;
+      } else {
+        accumulated_error = 0.0;
+      }
+
+      /* Correct time */
+
+      new_sys_time.tv_sec = rtc_t;
+      /* Average error in the RTC reading */
+      new_sys_time.tv_nsec = 500000000;
+
+      UTI_AddDoubleToTimespec(&new_sys_time, -accumulated_error, &new_sys_time);
+
+      if (new_sys_time.tv_sec < driftfile_time) {
+        LOG(LOGS_WARN, "RTC time before last driftfile modification (ignored)");
+        return 0;
+      }
+
+      sys_offset = UTI_DiffTimespecsToDouble(&old_sys_time, &new_sys_time);
+
+      /* Set system time only if the step is larger than 1 second */
+      if (fabs(sys_offset) >= 1.0) {
+        if (LCL_ApplyStepOffset(sys_offset))
+          LOG(LOGS_INFO, "System time set from RTC");
+      }
+    } else {
+      return 0;
+    }
+  } else {
+    return 0;
+  }
+
+  return 1;
+}
+
+/* ================================================== */
+
+int
+RTC_Linux_GetReport(RPT_RTC_Report *report)
+{
+  report->ref_time.tv_sec = coef_ref_time;
+  report->ref_time.tv_nsec = 0;
+  report->n_samples = n_samples;
+  report->n_runs = n_runs;
+  if (n_samples > 1) {
+    report->span_seconds = ((rtc_sec[n_samples-1] - rtc_sec[0]) +
+                            (long)(rtc_trim[n_samples-1] - rtc_trim[0]));
+  } else {
+    report->span_seconds = 0;
+  }
+  report->rtc_seconds_fast = coef_seconds_fast;
+  report->rtc_gain_rate_ppm = 1.0e6 * coef_gain_rate;
+  return 1;
+}
+
+/* ================================================== */
+
+int
+RTC_Linux_Trim(void)
+{
+  struct timespec now;
+
+  /* Remember the slope coefficient - we won't be able to determine a
+     good one in a few seconds when we determine the new offset! */
+  saved_coef_gain_rate = coef_gain_rate;
+
+  if (fabs(coef_seconds_fast) > 1.0) {
+
+    LOG(LOGS_INFO, "RTC wrong by %.3f seconds (step)",
+        coef_seconds_fast);
+
+    /* Do processing to set clock.  Let R be the value we set the
+       RTC to, then in 500ms the RTC ticks (R+1) (see comments in
+       arch/i386/kernel/time.c about the behaviour of the real time
+       clock chip).  If S is the system time now, the error at the
+       next RTC tick is given by E = (R+1) - (S+0.5).  Ideally we
+       want |E| <= 0.5, which implies R <= S <= R+1, i.e. R is just
+       the rounded down part of S, i.e. the seconds part. */
+
+    LCL_ReadCookedTime(&now, NULL);
+    
+    set_rtc(now.tv_sec);
+
+    /* All old samples will now look bogus under the new
+           regime. */
+    n_samples = 0;
+    operating_mode = OM_AFTERTRIM;
+
+    /* Estimate the offset in case writertc is called or chronyd
+       is terminated during rapid sampling */
+    coef_seconds_fast = -now.tv_nsec / 1.0e9 + 0.5;
+    coef_ref_time = now.tv_sec;
+
+    /* And start rapid sampling, interrupts on now */
+    SCH_RemoveTimeout(timeout_id);
+    timeout_id = 0;
+    switch_interrupts(1);
+  }
+
+  return 1;
+  
+}
diff --git a/chrony_3_3/rtc_linux.h b/chrony_3_3/rtc_linux.h
new file mode 100644
index 0000000..fa33ef1
--- /dev/null
+++ b/chrony_3_3/rtc_linux.h
@@ -0,0 +1,45 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  ======================================================================
+
+  */
+
+#ifndef _GOT_RTC_LINUX_H
+#define _GOT_RTC_LINUX_H
+
+#include "reports.h"
+
+extern int RTC_Linux_Initialise(void);
+extern void RTC_Linux_Finalise(void);
+extern int RTC_Linux_TimePreInit(time_t driftile_time);
+extern void RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything);
+extern void RTC_Linux_StartMeasurements(void);
+
+/* 0=success, 1=no driver, 2=can't write file */
+extern int RTC_Linux_WriteParameters(void);
+
+extern int RTC_Linux_GetReport(RPT_RTC_Report *report);
+extern int RTC_Linux_Trim(void);
+
+extern void RTC_Linux_CycleLogFile(void);
+
+#endif /* _GOT_RTC_LINUX_H */
diff --git a/chrony_3_3/sched.c b/chrony_3_3/sched.c
new file mode 100644
index 0000000..45ef11c
--- /dev/null
+++ b/chrony_3_3/sched.c
@@ -0,0 +1,795 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2011, 2013-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  This file contains the scheduling loop and the timeout queue.
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "array.h"
+#include "sched.h"
+#include "memory.h"
+#include "util.h"
+#include "local.h"
+#include "logging.h"
+
+/* ================================================== */
+
+/* Flag indicating that we are initialised */
+static int initialised = 0;
+
+/* ================================================== */
+
+/* One more than the highest file descriptor that is registered */
+static unsigned int one_highest_fd;
+
+#ifndef FD_SETSIZE
+/* If FD_SETSIZE is not defined, assume that fd_set is implemented
+   as a fixed size array of bits, possibly embedded inside a record */
+#define FD_SETSIZE (sizeof(fd_set) * 8)
+#endif
+
+typedef struct {
+  SCH_FileHandler       handler;
+  SCH_ArbitraryArgument arg;
+  int                   events;
+} FileHandlerEntry;
+
+static ARR_Instance file_handlers;
+
+/* Timestamp when last select() returned */
+static struct timespec last_select_ts, last_select_ts_raw;
+static double last_select_ts_err;
+
+/* ================================================== */
+
+/* Variables to handler the timer queue */
+
+typedef struct _TimerQueueEntry
+{
+  struct _TimerQueueEntry *next; /* Forward and back links in the list */
+  struct _TimerQueueEntry *prev;
+  struct timespec ts;           /* Local system time at which the
+                                   timeout is to expire.  Clearly this
+                                   must be in terms of what the
+                                   operating system thinks of as
+                                   system time, because it will be an
+                                   argument to select().  Therefore,
+                                   any fudges etc that our local time
+                                   driver module would apply to time
+                                   that we pass to clients etc doesn't
+                                   apply to this. */
+  SCH_TimeoutID id;             /* ID to allow client to delete
+                                   timeout */
+  SCH_TimeoutClass class;       /* The class that the epoch is in */
+  SCH_TimeoutHandler handler;   /* The handler routine to use */
+  SCH_ArbitraryArgument arg;    /* The argument to pass to the handler */
+
+} TimerQueueEntry;
+
+/* The timer queue.  We only use the next and prev entries of this
+   record, these chain to the real entries. */
+static TimerQueueEntry timer_queue;
+static unsigned long n_timer_queue_entries;
+static SCH_TimeoutID next_tqe_id;
+
+/* Pointer to head of free list */
+static TimerQueueEntry *tqe_free_list = NULL;
+
+/* Timestamp when was last timeout dispatched for each class */
+static struct timespec last_class_dispatch[SCH_NumberOfClasses];
+
+/* ================================================== */
+
+static int need_to_exit;
+
+/* ================================================== */
+
+static void
+handle_slew(struct timespec *raw,
+            struct timespec *cooked,
+            double dfreq,
+            double doffset,
+            LCL_ChangeType change_type,
+            void *anything);
+
+/* ================================================== */
+
+void
+SCH_Initialise(void)
+{
+  file_handlers = ARR_CreateInstance(sizeof (FileHandlerEntry));
+
+  n_timer_queue_entries = 0;
+  next_tqe_id = 0;
+
+  timer_queue.next = &timer_queue;
+  timer_queue.prev = &timer_queue;
+
+  need_to_exit = 0;
+
+  LCL_AddParameterChangeHandler(handle_slew, NULL);
+
+  LCL_ReadRawTime(&last_select_ts_raw);
+  last_select_ts = last_select_ts_raw;
+
+  initialised = 1;
+}
+
+
+/* ================================================== */
+
+void
+SCH_Finalise(void) {
+  ARR_DestroyInstance(file_handlers);
+
+  initialised = 0;
+}
+
+/* ================================================== */
+
+void
+SCH_AddFileHandler
+(int fd, int events, SCH_FileHandler handler, SCH_ArbitraryArgument arg)
+{
+  FileHandlerEntry *ptr;
+
+  assert(initialised);
+  assert(events);
+  assert(fd >= 0);
+  
+  if (fd >= FD_SETSIZE)
+    LOG_FATAL("Too many file descriptors");
+
+  /* Resize the array if the descriptor is highest so far */
+  while (ARR_GetSize(file_handlers) <= fd) {
+    ptr = ARR_GetNewElement(file_handlers);
+    ptr->handler = NULL;
+    ptr->arg = NULL;
+    ptr->events = 0;
+  }
+
+  ptr = ARR_GetElement(file_handlers, fd);
+
+  /* Don't want to allow the same fd to register a handler more than
+     once without deleting a previous association - this suggests
+     a bug somewhere else in the program. */
+  assert(!ptr->handler);
+
+  ptr->handler = handler;
+  ptr->arg = arg;
+  ptr->events = events;
+
+  if (one_highest_fd < fd + 1)
+    one_highest_fd = fd + 1;
+}
+
+
+/* ================================================== */
+
+void
+SCH_RemoveFileHandler(int fd)
+{
+  FileHandlerEntry *ptr;
+
+  assert(initialised);
+
+  ptr = ARR_GetElement(file_handlers, fd);
+
+  /* Check that a handler was registered for the fd in question */
+  assert(ptr->handler);
+
+  ptr->handler = NULL;
+  ptr->arg = NULL;
+  ptr->events = 0;
+
+  /* Find new highest file descriptor */
+  while (one_highest_fd > 0) {
+    ptr = ARR_GetElement(file_handlers, one_highest_fd - 1);
+    if (ptr->handler)
+      break;
+    one_highest_fd--;
+  }
+}
+
+/* ================================================== */
+
+void
+SCH_SetFileHandlerEvent(int fd, int event, int enable)
+{
+  FileHandlerEntry *ptr;
+
+  ptr = ARR_GetElement(file_handlers, fd);
+
+  if (enable)
+    ptr->events |= event;
+  else
+    ptr->events &= ~event;
+}
+
+/* ================================================== */
+
+void
+SCH_GetLastEventTime(struct timespec *cooked, double *err, struct timespec *raw)
+{
+  if (cooked) {
+    *cooked = last_select_ts;
+    if (err)
+      *err = last_select_ts_err;
+  }
+  if (raw)
+    *raw = last_select_ts_raw;
+}
+
+/* ================================================== */
+
+#define TQE_ALLOC_QUANTUM 32
+
+static TimerQueueEntry *
+allocate_tqe(void)
+{
+  TimerQueueEntry *new_block;
+  TimerQueueEntry *result;
+  int i;
+  if (tqe_free_list == NULL) {
+    new_block = MallocArray(TimerQueueEntry, TQE_ALLOC_QUANTUM);
+    for (i=1; i<TQE_ALLOC_QUANTUM; i++) {
+      new_block[i].next = &(new_block[i-1]);
+    }
+    new_block[0].next = NULL;
+    tqe_free_list = &(new_block[TQE_ALLOC_QUANTUM - 1]);
+  }
+
+  result = tqe_free_list;
+  tqe_free_list = tqe_free_list->next;
+  return result;
+}
+
+/* ================================================== */
+
+static void
+release_tqe(TimerQueueEntry *node)
+{
+  node->next = tqe_free_list;
+  tqe_free_list = node;
+}
+
+/* ================================================== */
+
+static SCH_TimeoutID
+get_new_tqe_id(void)
+{
+  TimerQueueEntry *ptr;
+
+try_again:
+  next_tqe_id++;
+  if (!next_tqe_id)
+    goto try_again;
+
+  /* Make sure the ID isn't already used */
+  for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next)
+    if (ptr->id == next_tqe_id)
+      goto try_again;
+
+  return next_tqe_id;
+}
+
+/* ================================================== */
+
+SCH_TimeoutID
+SCH_AddTimeout(struct timespec *ts, SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg)
+{
+  TimerQueueEntry *new_tqe;
+  TimerQueueEntry *ptr;
+
+  assert(initialised);
+
+  new_tqe = allocate_tqe();
+
+  new_tqe->id = get_new_tqe_id();
+  new_tqe->handler = handler;
+  new_tqe->arg = arg;
+  new_tqe->ts = *ts;
+  new_tqe->class = SCH_ReservedTimeoutValue;
+
+  /* Now work out where to insert the new entry in the list */
+  for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
+    if (UTI_CompareTimespecs(&new_tqe->ts, &ptr->ts) == -1) {
+      /* If the new entry comes before the current pointer location in
+         the list, we want to insert the new entry just before ptr. */
+      break;
+    }
+  }
+
+  /* At this stage, we want to insert the new entry immediately before
+     the entry identified by 'ptr' */
+
+  new_tqe->next = ptr;
+  new_tqe->prev = ptr->prev;
+  ptr->prev->next = new_tqe;
+  ptr->prev = new_tqe;
+
+  n_timer_queue_entries++;
+
+  return new_tqe->id;
+}
+
+/* ================================================== */
+/* This queues a timeout to elapse at a given delta time relative to
+   the current (raw) time */
+
+SCH_TimeoutID
+SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg)
+{
+  struct timespec now, then;
+
+  assert(initialised);
+  assert(delay >= 0.0);
+
+  LCL_ReadRawTime(&now);
+  UTI_AddDoubleToTimespec(&now, delay, &then);
+  if (UTI_CompareTimespecs(&now, &then) > 0) {
+    LOG_FATAL("Timeout overflow");
+  }
+
+  return SCH_AddTimeout(&then, handler, arg);
+
+}
+
+/* ================================================== */
+
+SCH_TimeoutID
+SCH_AddTimeoutInClass(double min_delay, double separation, double randomness,
+                      SCH_TimeoutClass class,
+                      SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg)
+{
+  TimerQueueEntry *new_tqe;
+  TimerQueueEntry *ptr;
+  struct timespec now;
+  double diff, r;
+  double new_min_delay;
+
+  assert(initialised);
+  assert(min_delay >= 0.0);
+  assert(class < SCH_NumberOfClasses);
+
+  if (randomness > 0.0) {
+    uint32_t rnd;
+
+    UTI_GetRandomBytes(&rnd, sizeof (rnd));
+    r = rnd * (randomness / (uint32_t)-1) + 1.0;
+    min_delay *= r;
+    separation *= r;
+  }
+  
+  LCL_ReadRawTime(&now);
+  new_min_delay = min_delay;
+
+  /* Check the separation from the last dispatched timeout */
+  diff = UTI_DiffTimespecsToDouble(&now, &last_class_dispatch[class]);
+  if (diff < separation && diff >= 0.0 && diff + new_min_delay < separation) {
+    new_min_delay = separation - diff;
+  }
+
+  /* Scan through list for entries in the same class and increase min_delay
+     if necessary to keep at least the separation away */
+  for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
+    if (ptr->class == class) {
+      diff = UTI_DiffTimespecsToDouble(&ptr->ts, &now);
+      if (new_min_delay > diff) {
+        if (new_min_delay - diff < separation) {
+          new_min_delay = diff + separation;
+        }
+      } else {
+        if (diff - new_min_delay < separation) {
+          new_min_delay = diff + separation;
+        }
+      }
+    }
+  }
+
+  for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
+    diff = UTI_DiffTimespecsToDouble(&ptr->ts, &now);
+    if (diff > new_min_delay) {
+      break;
+    }
+  }
+
+  /* We have located the insertion point */
+  new_tqe = allocate_tqe();
+
+  new_tqe->id = get_new_tqe_id();
+  new_tqe->handler = handler;
+  new_tqe->arg = arg;
+  UTI_AddDoubleToTimespec(&now, new_min_delay, &new_tqe->ts);
+  new_tqe->class = class;
+
+  new_tqe->next = ptr;
+  new_tqe->prev = ptr->prev;
+  ptr->prev->next = new_tqe;
+  ptr->prev = new_tqe;
+  n_timer_queue_entries++;
+
+  return new_tqe->id;
+}
+
+/* ================================================== */
+
+void
+SCH_RemoveTimeout(SCH_TimeoutID id)
+{
+  TimerQueueEntry *ptr;
+
+  assert(initialised);
+
+  if (!id)
+    return;
+
+  for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
+
+    if (ptr->id == id) {
+      /* Found the required entry */
+      
+      /* Unlink from the queue */
+      ptr->next->prev = ptr->prev;
+      ptr->prev->next = ptr->next;
+      
+      /* Decrement entry count */
+      --n_timer_queue_entries;
+      
+      /* Release memory back to the operating system */
+      release_tqe(ptr);
+
+      return;
+    }
+  }
+
+  /* Catch calls with invalid non-zero ID */
+  assert(0);
+}
+
+/* ================================================== */
+/* Try to dispatch any timeouts that have already gone by, and
+   keep going until all are done.  (The earlier ones may take so
+   long to do that the later ones come around by the time they are
+   completed). */
+
+static void
+dispatch_timeouts(struct timespec *now) {
+  TimerQueueEntry *ptr;
+  SCH_TimeoutHandler handler;
+  SCH_ArbitraryArgument arg;
+  int n_done = 0, n_entries_on_start = n_timer_queue_entries;
+
+  while (1) {
+    LCL_ReadRawTime(now);
+
+    if (!(n_timer_queue_entries > 0 &&
+          UTI_CompareTimespecs(now, &timer_queue.next->ts) >= 0)) {
+      break;
+    }
+
+    ptr = timer_queue.next;
+
+    last_class_dispatch[ptr->class] = *now;
+
+    handler = ptr->handler;
+    arg = ptr->arg;
+
+    SCH_RemoveTimeout(ptr->id);
+
+    /* Dispatch the handler */
+    (handler)(arg);
+
+    /* Increment count of timeouts handled */
+    ++n_done;
+
+    /* If more timeouts were handled than there were in the timer queue on
+       start and there are now, assume some code is scheduling timeouts with
+       negative delays and abort.  Make the actual limit higher in case the
+       machine is temporarily overloaded and dispatching the handlers takes
+       more time than was delay of a scheduled timeout. */
+    if (n_done > n_timer_queue_entries * 4 &&
+        n_done > n_entries_on_start * 4) {
+      LOG_FATAL("Possible infinite loop in scheduling");
+    }
+  }
+}
+
+/* ================================================== */
+
+/* nfd is the number of bits set in all fd_sets */
+
+static void
+dispatch_filehandlers(int nfd, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds)
+{
+  FileHandlerEntry *ptr;
+  int fd;
+  
+  for (fd = 0; nfd && fd < one_highest_fd; fd++) {
+    if (except_fds && FD_ISSET(fd, except_fds)) {
+      /* This descriptor has an exception, dispatch its handler */
+      ptr = (FileHandlerEntry *)ARR_GetElement(file_handlers, fd);
+      (ptr->handler)(fd, SCH_FILE_EXCEPTION, ptr->arg);
+      nfd--;
+
+      /* Don't try to read from it now */
+      if (read_fds && FD_ISSET(fd, read_fds)) {
+        FD_CLR(fd, read_fds);
+        nfd--;
+      }
+    }
+
+    if (read_fds && FD_ISSET(fd, read_fds)) {
+      /* This descriptor can be read from, dispatch its handler */
+      ptr = (FileHandlerEntry *)ARR_GetElement(file_handlers, fd);
+      (ptr->handler)(fd, SCH_FILE_INPUT, ptr->arg);
+      nfd--;
+    }
+
+    if (write_fds && FD_ISSET(fd, write_fds)) {
+      /* This descriptor can be written to, dispatch its handler */
+      ptr = (FileHandlerEntry *)ARR_GetElement(file_handlers, fd);
+      (ptr->handler)(fd, SCH_FILE_OUTPUT, ptr->arg);
+      nfd--;
+    }
+  }
+}
+
+/* ================================================== */
+
+static void
+handle_slew(struct timespec *raw,
+            struct timespec *cooked,
+            double dfreq,
+            double doffset,
+            LCL_ChangeType change_type,
+            void *anything)
+{
+  TimerQueueEntry *ptr;
+  double delta;
+  int i;
+
+  if (change_type != LCL_ChangeAdjust) {
+    /* Make sure this handler is invoked first in order to not shift new timers
+       added from other handlers */
+    assert(LCL_IsFirstParameterChangeHandler(handle_slew));
+
+    /* If a step change occurs, just shift all raw time stamps by the offset */
+    
+    for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
+      UTI_AddDoubleToTimespec(&ptr->ts, -doffset, &ptr->ts);
+    }
+
+    for (i = 0; i < SCH_NumberOfClasses; i++) {
+      UTI_AddDoubleToTimespec(&last_class_dispatch[i], -doffset, &last_class_dispatch[i]);
+    }
+
+    UTI_AddDoubleToTimespec(&last_select_ts_raw, -doffset, &last_select_ts_raw);
+  }
+
+  UTI_AdjustTimespec(&last_select_ts, cooked, &last_select_ts, &delta, dfreq, doffset);
+}
+
+/* ================================================== */
+
+static void
+fill_fd_sets(fd_set **read_fds, fd_set **write_fds, fd_set **except_fds)
+{
+  FileHandlerEntry *handlers;
+  fd_set *rd, *wr, *ex;
+  int i, n, events;
+
+  n = ARR_GetSize(file_handlers);
+  handlers = ARR_GetElements(file_handlers);
+  rd = wr = ex = NULL;
+
+  for (i = 0; i < n; i++) {
+    events = handlers[i].events;
+
+    if (!events)
+      continue;
+
+    if (events & SCH_FILE_INPUT) {
+      if (!rd) {
+        rd = *read_fds;
+        FD_ZERO(rd);
+      }
+      FD_SET(i, rd);
+    }
+
+    if (events & SCH_FILE_OUTPUT) {
+      if (!wr) {
+        wr = *write_fds;
+        FD_ZERO(wr);
+      }
+      FD_SET(i, wr);
+    }
+
+    if (events & SCH_FILE_EXCEPTION) {
+      if (!ex) {
+        ex = *except_fds;
+        FD_ZERO(ex);
+      }
+      FD_SET(i, ex);
+    }
+  }
+
+  if (!rd)
+    *read_fds = NULL;
+  if (!wr)
+    *write_fds = NULL;
+  if (!ex)
+    *except_fds = NULL;
+}
+
+/* ================================================== */
+
+#define JUMP_DETECT_THRESHOLD 10
+
+static int
+check_current_time(struct timespec *prev_raw, struct timespec *raw, int timeout,
+                   struct timeval *orig_select_tv,
+                   struct timeval *rem_select_tv)
+{
+  struct timespec elapsed_min, elapsed_max, orig_select_ts, rem_select_ts;
+  double step, elapsed;
+
+  UTI_TimevalToTimespec(orig_select_tv, &orig_select_ts);
+
+  /* Get an estimate of the time spent waiting in the select() call. On some
+     systems (e.g. Linux) the timeout timeval is modified to return the
+     remaining time, use that information. */
+  if (timeout) {
+    elapsed_max = elapsed_min = orig_select_ts;
+  } else if (rem_select_tv && rem_select_tv->tv_sec >= 0 &&
+             rem_select_tv->tv_sec <= orig_select_tv->tv_sec &&
+             (rem_select_tv->tv_sec != orig_select_tv->tv_sec ||
+              rem_select_tv->tv_usec != orig_select_tv->tv_usec)) {
+    UTI_TimevalToTimespec(rem_select_tv, &rem_select_ts);
+    UTI_DiffTimespecs(&elapsed_min, &orig_select_ts, &rem_select_ts);
+    elapsed_max = elapsed_min;
+  } else {
+    if (rem_select_tv)
+      elapsed_max = orig_select_ts;
+    else
+      UTI_DiffTimespecs(&elapsed_max, raw, prev_raw);
+    UTI_ZeroTimespec(&elapsed_min);
+  }
+
+  if (last_select_ts_raw.tv_sec + elapsed_min.tv_sec >
+      raw->tv_sec + JUMP_DETECT_THRESHOLD) {
+    LOG(LOGS_WARN, "Backward time jump detected!");
+  } else if (prev_raw->tv_sec + elapsed_max.tv_sec + JUMP_DETECT_THRESHOLD <
+             raw->tv_sec) {
+    LOG(LOGS_WARN, "Forward time jump detected!");
+  } else {
+    return 1;
+  }
+
+  step = UTI_DiffTimespecsToDouble(&last_select_ts_raw, raw);
+  elapsed = UTI_TimespecToDouble(&elapsed_min);
+  step += elapsed;
+
+  /* Cooked time may no longer be valid after dispatching the handlers */
+  LCL_NotifyExternalTimeStep(raw, raw, step, fabs(step));
+
+  return 0;
+}
+
+/* ================================================== */
+
+void
+SCH_MainLoop(void)
+{
+  fd_set read_fds, write_fds, except_fds;
+  fd_set *p_read_fds, *p_write_fds, *p_except_fds;
+  int status, errsv;
+  struct timeval tv, saved_tv, *ptv;
+  struct timespec ts, now, saved_now, cooked;
+  double err;
+
+  assert(initialised);
+
+  while (!need_to_exit) {
+    /* Dispatch timeouts and fill now with current raw time */
+    dispatch_timeouts(&now);
+    saved_now = now;
+    
+    /* The timeout handlers may request quit */
+    if (need_to_exit)
+      break;
+
+    /* Check whether there is a timeout and set it up */
+    if (n_timer_queue_entries > 0) {
+      UTI_DiffTimespecs(&ts, &timer_queue.next->ts, &now);
+      assert(ts.tv_sec > 0 || ts.tv_nsec > 0);
+
+      UTI_TimespecToTimeval(&ts, &tv);
+      ptv = &tv;
+      saved_tv = tv;
+    } else {
+      ptv = NULL;
+      saved_tv.tv_sec = saved_tv.tv_usec = 0;
+    }
+
+    p_read_fds = &read_fds;
+    p_write_fds = &write_fds;
+    p_except_fds = &except_fds;
+    fill_fd_sets(&p_read_fds, &p_write_fds, &p_except_fds);
+
+    /* if there are no file descriptors being waited on and no
+       timeout set, this is clearly ridiculous, so stop the run */
+    if (!ptv && !p_read_fds && !p_write_fds)
+      LOG_FATAL("Nothing to do");
+
+    status = select(one_highest_fd, p_read_fds, p_write_fds, p_except_fds, ptv);
+    errsv = errno;
+
+    LCL_ReadRawTime(&now);
+    LCL_CookTime(&now, &cooked, &err);
+
+    /* Check if the time didn't jump unexpectedly */
+    if (!check_current_time(&saved_now, &now, status == 0, &saved_tv, ptv)) {
+      /* Cook the time again after handling the step */
+      LCL_CookTime(&now, &cooked, &err);
+    }
+
+    last_select_ts_raw = now;
+    last_select_ts = cooked;
+    last_select_ts_err = err;
+
+    if (status < 0) {
+      if (!need_to_exit && errsv != EINTR) {
+        LOG_FATAL("select() failed : %s", strerror(errsv));
+      }
+    } else if (status > 0) {
+      /* A file descriptor is ready for input or output */
+      dispatch_filehandlers(status, p_read_fds, p_write_fds, p_except_fds);
+    } else {
+      /* No descriptors readable, timeout must have elapsed.
+       Therefore, tv must be non-null */
+      assert(ptv);
+
+      /* There's nothing to do here, since the timeouts
+         will be dispatched at the top of the next loop
+         cycle */
+
+    }
+  }         
+}
+
+/* ================================================== */
+
+void
+SCH_QuitProgram(void)
+{
+  need_to_exit = 1;
+}
+
+/* ================================================== */
+
diff --git a/chrony_3_3/sched.h b/chrony_3_3/sched.h
new file mode 100644
index 0000000..5ff53c7
--- /dev/null
+++ b/chrony_3_3/sched.h
@@ -0,0 +1,89 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Exported header file for sched.c
+  */
+
+#ifndef GOT_SCHED_H
+#define GOT_SCHED_H
+
+#include "sysincl.h"
+
+/* Type for timeout IDs, valid IDs are always greater than zero */
+typedef unsigned int SCH_TimeoutID;
+
+typedef enum {
+  SCH_ReservedTimeoutValue = 0,
+  SCH_NtpClientClass,
+  SCH_NtpPeerClass,
+  SCH_NtpBroadcastClass,
+  SCH_NumberOfClasses /* needs to be last */
+} SCH_TimeoutClass;
+
+typedef void* SCH_ArbitraryArgument;
+typedef void (*SCH_FileHandler)(int fd, int event, SCH_ArbitraryArgument);
+typedef void (*SCH_TimeoutHandler)(SCH_ArbitraryArgument);
+
+/* Exported functions */
+
+/* Initialisation function for the module */
+extern void SCH_Initialise(void);
+
+/* Finalisation function for the module */
+extern void SCH_Finalise(void);
+
+/* File events */
+#define SCH_FILE_INPUT 1
+#define SCH_FILE_OUTPUT 2
+#define SCH_FILE_EXCEPTION 4
+
+/* Register a handler for when select goes true on a file descriptor */
+extern void SCH_AddFileHandler(int fd, int events, SCH_FileHandler handler, SCH_ArbitraryArgument arg);
+extern void SCH_RemoveFileHandler(int fd);
+extern void SCH_SetFileHandlerEvent(int fd, int event, int enable);
+
+/* Get the time stamp taken after a file descriptor became ready or a timeout expired */
+extern void SCH_GetLastEventTime(struct timespec *cooked, double *err, struct timespec *raw);
+
+/* This queues a timeout to elapse at a given (raw) local time */
+extern SCH_TimeoutID SCH_AddTimeout(struct timespec *ts, SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg);
+
+/* This queues a timeout to elapse at a given delta time relative to the current (raw) time */
+extern SCH_TimeoutID SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler, SCH_ArbitraryArgument);
+
+/* This queues a timeout in a particular class, ensuring that the
+   expiry time is at least a given separation away from any other
+   timeout in the same class, given randomness is added to the delay
+   and separation */
+extern SCH_TimeoutID SCH_AddTimeoutInClass(double min_delay, double separation, double randomness,
+                                           SCH_TimeoutClass class,
+                                           SCH_TimeoutHandler handler, SCH_ArbitraryArgument);
+
+/* The next one probably ought to return a status code */
+extern void SCH_RemoveTimeout(SCH_TimeoutID);
+
+extern void SCH_MainLoop(void);
+
+extern void SCH_QuitProgram(void);
+
+#endif /* GOT_SCHED_H */
diff --git a/chrony_3_3/smooth.c b/chrony_3_3/smooth.c
new file mode 100644
index 0000000..a21dcd8
--- /dev/null
+++ b/chrony_3_3/smooth.c
@@ -0,0 +1,364 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2015
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Routines implementing time smoothing.
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "conf.h"
+#include "local.h"
+#include "logging.h"
+#include "reference.h"
+#include "smooth.h"
+#include "util.h"
+
+/*
+  Time smoothing determines an offset that needs to be applied to the cooked
+  time to make it smooth for external observers.  Observed offset and frequency
+  change slowly and there are no discontinuities.  This can be used on an NTP
+  server to make it easier for the clients to track the time and keep their
+  clocks close together even when large offset or frequency corrections are
+  applied to the server's clock (e.g. after being offline for longer time).
+
+  Accumulated offset and frequency are smoothed out in three stages.  In the
+  first stage, the frequency is changed at a constant rate (wander) up to a
+  maximum, in the second stage the frequency stays at the maximum for as long
+  as needed and in the third stage the frequency is brought back to zero.
+
+              |
+    max_freq  +-------/--------\-------------
+              |      /|        |\
+        freq  |     / |        | \
+              |    /  |        |  \
+              |   /   |        |   \
+           0  +--/----+--------+----\--------
+              | /     |        |    |    time
+              |/      |        |    |
+
+        stage     1       2      3
+
+  Integral of this function is the smoothed out offset.  It's a continuous
+  piecewise polynomial with two quadratic parts and one linear.
+*/
+
+struct stage {
+  double wander;
+  double length;
+};
+
+#define NUM_STAGES 3
+
+static struct stage stages[NUM_STAGES];
+
+/* Enabled/disabled smoothing */
+static int enabled;
+
+/* Enabled/disabled mode where only leap seconds are smoothed out and normal
+   offset/frequency changes are ignored */
+static int leap_only_mode;
+
+/* Maximum skew/max_wander ratio to start updating offset and frequency */
+#define UNLOCK_SKEW_WANDER_RATIO 10000
+
+static int locked;
+
+/* Maximum wander and frequency offset */
+static double max_wander;
+static double max_freq;
+
+/* Frequency offset, time offset and the time of the last smoothing update */
+static double smooth_freq;
+static double smooth_offset;
+static struct timespec last_update;
+
+
+static void
+get_smoothing(struct timespec *now, double *poffset, double *pfreq,
+              double *pwander)
+{
+  double elapsed, length, offset, freq, wander;
+  int i;
+
+  elapsed = UTI_DiffTimespecsToDouble(now, &last_update);
+
+  offset = smooth_offset;
+  freq = smooth_freq;
+  wander = 0.0;
+
+  for (i = 0; i < NUM_STAGES; i++) {
+    if (elapsed <= 0.0)
+      break;
+
+    length = stages[i].length;
+    if (length >= elapsed)
+      length = elapsed;
+
+    wander = stages[i].wander;
+    offset -= length * (2.0 * freq + wander * length) / 2.0;
+    freq += wander * length;
+    elapsed -= length;
+  }
+
+  if (elapsed > 0.0) {
+    wander = 0.0;
+    offset -= elapsed * freq;
+  }
+
+  *poffset = offset;
+  *pfreq = freq;
+  if (pwander)
+    *pwander = wander;
+}
+
+static void
+update_stages(void)
+{
+  double s1, s2, s, l1, l2, l3, lc, f, f2, l1t[2], l3t[2], err[2];
+  int i, dir;
+
+  /* Prepare the three stages so that the integral of the frequency offset
+     is equal to the offset that should be smoothed out */
+
+  s1 = smooth_offset / max_wander;
+  s2 = smooth_freq * smooth_freq / (2.0 * max_wander * max_wander);
+  
+  /* Calculate the lengths of the 1st and 3rd stage assuming there is no
+     frequency limit.  The direction of the 1st stage is selected so that
+     the lengths will not be negative.  With extremely small offsets both
+     directions may give a negative length due to numerical errors, so select
+     the one which gives a smaller error. */
+
+  for (i = 0, dir = -1; i <= 1; i++, dir += 2) {
+    err[i] = 0.0;
+    s = dir * s1 + s2;
+
+    if (s < 0.0) {
+      err[i] += -s;
+      s = 0.0;
+    }
+
+    l3t[i] = sqrt(s);
+    l1t[i] = l3t[i] - dir * smooth_freq / max_wander;
+
+    if (l1t[i] < 0.0) {
+      err[i] += l1t[i] * l1t[i];
+      l1t[i] = 0.0;
+    }
+  }
+
+  if (err[0] < err[1]) {
+    l1 = l1t[0];
+    l3 = l3t[0];
+    dir = -1;
+  } else {
+    l1 = l1t[1];
+    l3 = l3t[1];
+    dir = 1;
+  }
+
+  l2 = 0.0;
+
+  /* If the limit was reached, shorten 1st+3rd stages and set a 2nd stage */
+  f = dir * smooth_freq + l1 * max_wander - max_freq;
+  if (f > 0.0) {
+    lc = f / max_wander;
+
+    /* No 1st stage if the frequency is already above the maximum */
+    if (lc > l1) {
+      lc = l1;
+      f2 = dir * smooth_freq;
+    } else {
+      f2 = max_freq;
+    }
+
+    l2 = lc * (2.0 + f / f2);
+    l1 -= lc;
+    l3 -= lc;
+  }
+
+  stages[0].wander = dir * max_wander;
+  stages[0].length = l1;
+  stages[1].wander = 0.0;
+  stages[1].length = l2;
+  stages[2].wander = -dir * max_wander;
+  stages[2].length = l3;
+
+  for (i = 0; i < NUM_STAGES; i++) {
+    DEBUG_LOG("Smooth stage %d wander %e length %f",
+              i + 1, stages[i].wander, stages[i].length);
+  }
+}
+
+static void
+update_smoothing(struct timespec *now, double offset, double freq)
+{
+  /* Don't accept offset/frequency until the clock has stabilized */
+  if (locked) {
+    if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO || leap_only_mode)
+      SMT_Activate(now);
+    return;
+  }
+
+  get_smoothing(now, &smooth_offset, &smooth_freq, NULL);
+  smooth_offset += offset;
+  smooth_freq = (smooth_freq - freq) / (1.0 - freq);
+  last_update = *now;
+
+  update_stages();
+
+  DEBUG_LOG("Smooth offset %e freq %e", smooth_offset, smooth_freq);
+}
+
+static void
+handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
+            double doffset, LCL_ChangeType change_type, void *anything)
+{
+  double delta;
+
+  if (change_type == LCL_ChangeAdjust) {
+    if (leap_only_mode)
+      update_smoothing(cooked, 0.0, 0.0);
+    else
+      update_smoothing(cooked, doffset, dfreq);
+  }
+
+  if (!UTI_IsZeroTimespec(&last_update))
+    UTI_AdjustTimespec(&last_update, cooked, &last_update, &delta, dfreq, doffset);
+}
+
+void SMT_Initialise(void)
+{
+  CNF_GetSmooth(&max_freq, &max_wander, &leap_only_mode);
+  if (max_freq <= 0.0 || max_wander <= 0.0) {
+      enabled = 0;
+      return;
+  }
+
+  enabled = 1;
+  locked = 1;
+
+  /* Convert from ppm */
+  max_freq *= 1e-6;
+  max_wander *= 1e-6;
+
+  UTI_ZeroTimespec(&last_update);
+
+  LCL_AddParameterChangeHandler(handle_slew, NULL);
+}
+
+void SMT_Finalise(void)
+{
+}
+
+int SMT_IsEnabled(void)
+{
+  return enabled;
+}
+
+double
+SMT_GetOffset(struct timespec *now)
+{
+  double offset, freq;
+
+  if (!enabled)
+    return 0.0;
+  
+  get_smoothing(now, &offset, &freq, NULL);
+
+  return offset;
+}
+
+void
+SMT_Activate(struct timespec *now)
+{
+  if (!enabled || !locked)
+    return;
+
+  LOG(LOGS_INFO, "Time smoothing activated%s", leap_only_mode ?
+      " (leap seconds only)" : "");
+  locked = 0;
+  last_update = *now;
+}
+
+void
+SMT_Reset(struct timespec *now)
+{
+  int i;
+
+  if (!enabled)
+    return;
+
+  smooth_offset = 0.0;
+  smooth_freq = 0.0;
+  last_update = *now;
+
+  for (i = 0; i < NUM_STAGES; i++)
+    stages[i].wander = stages[i].length = 0.0;
+}
+
+void
+SMT_Leap(struct timespec *now, int leap)
+{
+  /* When the leap-only mode is disabled, the leap second will be accumulated
+     in handle_slew() as a normal offset */
+  if (!enabled || !leap_only_mode)
+    return;
+
+  update_smoothing(now, leap, 0.0);
+}
+
+int
+SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timespec *now)
+{
+  double length, elapsed;
+  int i;
+
+  if (!enabled)
+    return 0;
+
+  report->active = !locked;
+  report->leap_only = leap_only_mode;
+
+  get_smoothing(now, &report->offset, &report->freq_ppm, &report->wander_ppm);
+
+  /* Convert to ppm and negate (positive values mean faster/speeding up) */
+  report->freq_ppm *= -1.0e6;
+  report->wander_ppm *= -1.0e6;
+
+  elapsed = UTI_DiffTimespecsToDouble(now, &last_update);
+  if (!locked && elapsed >= 0.0) {
+    for (i = 0, length = 0.0; i < NUM_STAGES; i++)
+      length += stages[i].length;
+    report->last_update_ago = elapsed;
+    report->remaining_time = elapsed < length ? length - elapsed : 0.0;
+  } else {
+    report->last_update_ago = 0.0;
+    report->remaining_time = 0.0;
+  }
+
+  return 1;
+}
diff --git a/chrony_3_3/smooth.h b/chrony_3_3/smooth.h
new file mode 100644
index 0000000..4e84504
--- /dev/null
+++ b/chrony_3_3/smooth.h
@@ -0,0 +1,48 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2015
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  This module implements time smoothing.
+  */
+
+#ifndef GOT_SMOOTH_H
+#define GOT_SMOOTH_H
+
+#include "reports.h"
+
+extern void SMT_Initialise(void);
+
+extern void SMT_Finalise(void);
+
+extern int SMT_IsEnabled(void);
+
+extern double SMT_GetOffset(struct timespec *now);
+
+extern void SMT_Activate(struct timespec *now);
+
+extern void SMT_Reset(struct timespec *now);
+
+extern void SMT_Leap(struct timespec *now, int leap);
+
+extern int SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timespec *now);
+
+#endif
diff --git a/chrony_3_3/sources.c b/chrony_3_3/sources.c
new file mode 100644
index 0000000..8aaa4a6
--- /dev/null
+++ b/chrony_3_3/sources.c
@@ -0,0 +1,1400 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2011-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  The routines in this file manage the complete pool of sources that
+  we might be synchronizing to.  This includes NTP sources and others
+  (e.g. local reference clocks, eyeball + wristwatch etc).
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "sources.h"
+#include "sourcestats.h"
+#include "memory.h"
+#include "ntp.h" /* For NTP_Leap */
+#include "ntp_sources.h"
+#include "local.h"
+#include "reference.h"
+#include "util.h"
+#include "conf.h"
+#include "logging.h"
+#include "reports.h"
+#include "nameserv.h"
+#include "sched.h"
+#include "regress.h"
+
+/* ================================================== */
+/* Flag indicating that we are initialised */
+static int initialised = 0;
+
+/* ================================================== */
+/* Structure used to hold info for selecting between sources */
+struct SelectInfo {
+  int stratum;
+  int select_ok;
+  double std_dev;
+  double root_distance;
+  double lo_limit;
+  double hi_limit;
+  double last_sample_ago;
+};
+
+/* ================================================== */
+/* This enum contains the flag values that are used to label
+   each source */
+typedef enum {
+  SRC_OK,               /* OK so far, not a final status! */
+  SRC_UNSELECTABLE,     /* Has noselect option set */
+  SRC_BAD_STATS,        /* Doesn't have valid stats data */
+  SRC_BAD_DISTANCE,     /* Has root distance longer than allowed maximum */
+  SRC_JITTERY,          /* Had std dev larger than allowed maximum */
+  SRC_WAITS_STATS,      /* Others have bad stats, selection postponed */
+  SRC_STALE,            /* Has older samples than others */
+  SRC_ORPHAN,           /* Has stratum equal or larger than orphan stratum */
+  SRC_UNTRUSTED,        /* Overlaps trusted sources */
+  SRC_FALSETICKER,      /* Doesn't agree with others */
+  SRC_WAITS_SOURCES,    /* Not enough sources, selection postponed */
+  SRC_NONPREFERRED,     /* Others have prefer option */
+  SRC_WAITS_UPDATE,     /* No updates, selection postponed */
+  SRC_DISTANT,          /* Others have shorter root distance */
+  SRC_OUTLIER,          /* Outlier in clustering (not used yet) */
+  SRC_UNSELECTED,       /* Used for synchronisation, not system peer */
+  SRC_SELECTED,         /* Used for synchronisation, selected as system peer */
+} SRC_Status;
+
+/* ================================================== */
+/* Define the instance structure used to hold information about each
+   source */
+struct SRC_Instance_Record {
+  SST_Stats stats;
+  NTP_Leap leap_status;         /* Leap status */
+  int index;                    /* Index back into the array of source */
+  uint32_t ref_id;              /* The reference ID of this source
+                                   (i.e. from its IP address, NOT the
+                                   reference _it_ is sync'd to) */
+  IPAddr *ip_addr;              /* Its IP address if NTP source */
+
+  /* Flag indicating that the source is updating reachability */
+  int active;
+
+  /* Reachability register */
+  int reachability;
+
+  /* Number of set bits in the reachability register */
+  int reachability_size;
+
+  /* Updates since last reference update */
+  int updates;
+
+  /* Updates left before allowing combining */
+  int distant;
+
+  /* Flag indicating the status of the source */
+  SRC_Status status;
+
+  /* Type of the source */
+  SRC_Type type;
+
+  /* Options used when selecting sources */ 
+  int sel_options;
+
+  /* Score against currently selected source */
+  double sel_score;
+
+  struct SelectInfo sel_info;
+};
+
+/* ================================================== */
+/* Structure used to build the sort list for finding falsetickers */
+struct Sort_Element {
+  int index;
+  double offset;
+  enum {
+    LOW = -1,
+    HIGH = 1
+  } tag;
+};
+
+/* ================================================== */
+/* Table of sources */
+static struct SRC_Instance_Record **sources;
+static struct Sort_Element *sort_list;
+static int *sel_sources;
+static int n_sources; /* Number of sources currently in the table */
+static int max_n_sources; /* Capacity of the table */
+
+#define INVALID_SOURCE (-1)
+static int selected_source_index; /* Which source index is currently
+                                     selected (set to INVALID_SOURCE
+                                     if no current valid reference) */
+
+/* Score needed to replace the currently selected source */
+#define SCORE_LIMIT 10.0
+
+/* Number of updates needed to reset the distant status */
+#define DISTANT_PENALTY 32
+
+static double max_distance;
+static double max_jitter;
+static double reselect_distance;
+static double stratum_weight;
+static double combine_limit;
+
+/* ================================================== */
+/* Forward prototype */
+
+static void
+slew_sources(struct timespec *raw, struct timespec *cooked, double dfreq,
+             double doffset, LCL_ChangeType change_type, void *anything);
+static void
+add_dispersion(double dispersion, void *anything);
+static char *
+source_to_string(SRC_Instance inst);
+
+/* ================================================== */
+/* Initialisation function */
+void SRC_Initialise(void) {
+  sources = NULL;
+  sort_list = NULL;
+  sel_sources = NULL;
+  n_sources = 0;
+  max_n_sources = 0;
+  selected_source_index = INVALID_SOURCE;
+  max_distance = CNF_GetMaxDistance();
+  max_jitter = CNF_GetMaxJitter();
+  reselect_distance = CNF_GetReselectDistance();
+  stratum_weight = CNF_GetStratumWeight();
+  combine_limit = CNF_GetCombineLimit();
+  initialised = 1;
+
+  LCL_AddParameterChangeHandler(slew_sources, NULL);
+  LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
+}
+
+/* ================================================== */
+/* Finalisation function */
+void SRC_Finalise(void)
+{
+  LCL_RemoveParameterChangeHandler(slew_sources, NULL);
+  LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
+
+  Free(sources);
+  Free(sort_list);
+  Free(sel_sources);
+
+  initialised = 0;
+}
+
+/* ================================================== */
+/* Function to create a new instance.  This would be called by one of
+   the individual source-type instance creation routines. */
+
+SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options,
+                                   IPAddr *addr, int min_samples, int max_samples,
+                                   double min_delay, double asymmetry)
+{
+  SRC_Instance result;
+
+  assert(initialised);
+
+  if (min_samples == SRC_DEFAULT_MINSAMPLES)
+    min_samples = CNF_GetMinSamples();
+  if (max_samples == SRC_DEFAULT_MAXSAMPLES)
+    max_samples = CNF_GetMaxSamples();
+
+  result = MallocNew(struct SRC_Instance_Record);
+  result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples,
+                                     min_delay, asymmetry);
+
+  if (n_sources == max_n_sources) {
+    /* Reallocate memory */
+    max_n_sources = max_n_sources > 0 ? 2 * max_n_sources : 4;
+    if (sources) {
+      sources = ReallocArray(struct SRC_Instance_Record *, max_n_sources, sources);
+      sort_list = ReallocArray(struct Sort_Element, 3*max_n_sources, sort_list);
+      sel_sources = ReallocArray(int, max_n_sources, sel_sources);
+    } else {
+      sources = MallocArray(struct SRC_Instance_Record *, max_n_sources);
+      sort_list = MallocArray(struct Sort_Element, 3*max_n_sources);
+      sel_sources = MallocArray(int, max_n_sources);
+    }
+  }
+
+  sources[n_sources] = result;
+
+  result->index = n_sources;
+  result->type = type;
+  result->sel_options = sel_options;
+
+  SRC_SetRefid(result, ref_id, addr);
+  SRC_ResetInstance(result);
+
+  n_sources++;
+
+  return result;
+}
+
+/* ================================================== */
+/* Function to get rid of a source when it is being unconfigured.
+   This may cause the current reference source to be reselected, if this
+   was the reference source or contributed significantly to a
+   falseticker decision. */
+
+void SRC_DestroyInstance(SRC_Instance instance)
+{
+  int dead_index, i;
+
+  assert(initialised);
+
+  SST_DeleteInstance(instance->stats);
+  dead_index = instance->index;
+  for (i=dead_index; i<n_sources-1; i++) {
+    sources[i] = sources[i+1];
+    sources[i]->index = i;
+  }
+  --n_sources;
+  Free(instance);
+
+  /* If this was the previous reference source, we have to reselect! */
+  if (selected_source_index == dead_index)
+    SRC_ReselectSource();
+  else if (selected_source_index > dead_index)
+    --selected_source_index;
+}
+
+/* ================================================== */
+
+void
+SRC_ResetInstance(SRC_Instance instance)
+{
+  instance->leap_status = LEAP_Normal;
+  instance->active = 0;
+  instance->updates = 0;
+  instance->reachability = 0;
+  instance->reachability_size = 0;
+  instance->distant = 0;
+  instance->status = SRC_BAD_STATS;
+  instance->sel_score = 1.0;
+
+  SST_ResetInstance(instance->stats);
+}
+
+/* ================================================== */
+
+void
+SRC_SetRefid(SRC_Instance instance, uint32_t ref_id, IPAddr *addr)
+{
+  instance->ref_id = ref_id;
+  instance->ip_addr = addr;
+  SST_SetRefid(instance->stats, ref_id, addr);
+}
+
+/* ================================================== */
+
+SST_Stats
+SRC_GetSourcestats(SRC_Instance instance)
+{
+  assert(initialised);
+  return instance->stats;
+}
+
+/* ================================================== */
+
+/* This function is called by one of the source drivers when it has
+   a new sample that is to be accumulated.
+
+   This function causes the frequency estimation to be re-run for the
+   designated source, and the clock selection procedure to be re-run
+   afterwards.
+
+   Parameters are described in sources.h
+
+   */
+
+void SRC_AccumulateSample
+(SRC_Instance inst, 
+ struct timespec *sample_time,
+ double offset, 
+ double peer_delay,
+ double peer_dispersion,
+ double root_delay, 
+ double root_dispersion, 
+ int stratum,
+ NTP_Leap leap_status)
+{
+
+  assert(initialised);
+
+  inst->leap_status = leap_status;
+
+  DEBUG_LOG("ip=[%s] t=%s ofs=%f del=%f disp=%f str=%d",
+            source_to_string(inst), UTI_TimespecToString(sample_time), -offset,
+            root_delay, root_dispersion, stratum);
+
+  if (REF_IsLeapSecondClose()) {
+    LOG(LOGS_INFO, "Dropping sample around leap second");
+    return;
+  }
+
+  /* WE HAVE TO NEGATE OFFSET IN THIS CALL, IT IS HERE THAT THE SENSE OF OFFSET
+     IS FLIPPED */
+  SST_AccumulateSample(inst->stats, sample_time, -offset, peer_delay, peer_dispersion, root_delay, root_dispersion, stratum);
+  SST_DoNewRegression(inst->stats);
+}
+
+/* ================================================== */
+
+void
+SRC_SetActive(SRC_Instance inst)
+{
+  inst->active = 1;
+}
+
+/* ================================================== */
+
+void
+SRC_UnsetActive(SRC_Instance inst)
+{
+  inst->active = 0;
+}
+
+/* ================================================== */
+
+static int
+special_mode_end(void)
+{
+    int i;
+
+    for (i = 0; i < n_sources; i++) {
+      /* No updates from inactive sources */
+      if (!sources[i]->active)
+        continue;
+
+      /* Don't expect more updates than from an offline iburst NTP source */
+      if (sources[i]->reachability_size >= SOURCE_REACH_BITS - 1)
+        continue;
+
+      /* Check if the source could still have enough samples to be selectable */
+      if (SOURCE_REACH_BITS - 1 - sources[i]->reachability_size +
+            SST_Samples(sources[i]->stats) >= MIN_SAMPLES_FOR_REGRESS)
+        return 0;
+    }
+
+    return 1;
+}
+
+void
+SRC_UpdateReachability(SRC_Instance inst, int reachable)
+{
+  inst->reachability <<= 1;
+  inst->reachability |= !!reachable;
+  inst->reachability %= 1U << SOURCE_REACH_BITS;
+
+  if (inst->reachability_size < SOURCE_REACH_BITS)
+      inst->reachability_size++;
+
+  if (!reachable && inst->index == selected_source_index) {
+    /* Try to select a better source */
+    SRC_SelectSource(NULL);
+  }
+
+  /* Check if special reference update mode failed */
+  if (REF_GetMode() != REF_ModeNormal && special_mode_end()) {
+    REF_SetUnsynchronised();
+  }
+
+  /* Try to replace NTP sources that are unreachable, falsetickers, or
+     have root distance or jitter larger than the allowed maximums */
+  if (inst->type == SRC_NTP &&
+      ((!inst->reachability && inst->reachability_size == SOURCE_REACH_BITS) ||
+       inst->status == SRC_BAD_DISTANCE || inst->status == SRC_JITTERY ||
+       inst->status == SRC_FALSETICKER)) {
+    NSR_HandleBadSource(inst->ip_addr);
+  }
+}
+
+/* ================================================== */
+
+void
+SRC_ResetReachability(SRC_Instance inst)
+{
+  inst->reachability = 0;
+  inst->reachability_size = 0;
+  SRC_UpdateReachability(inst, 0);
+}
+
+/* ================================================== */
+
+static void
+log_selection_message(char *format, char *arg)
+{
+  if (REF_GetMode() != REF_ModeNormal)
+    return;
+  LOG(LOGS_INFO, format, arg);
+}
+
+/* ================================================== */
+
+static int
+compare_sort_elements(const void *a, const void *b)
+{
+  const struct Sort_Element *u = (const struct Sort_Element *) a;
+  const struct Sort_Element *v = (const struct Sort_Element *) b;
+
+  if (u->offset < v->offset) {
+    return -1;
+  } else if (u->offset > v->offset) {
+    return +1;
+  } else if (u->tag < v->tag) {
+    return -1;
+  } else if (u->tag > v->tag) {
+    return +1;
+  } else {
+    return 0;
+  }
+}
+
+/* ================================================== */
+
+static char *
+source_to_string(SRC_Instance inst)
+{
+  switch (inst->type) {
+    case SRC_NTP:
+      return UTI_IPToString(inst->ip_addr);
+    case SRC_REFCLOCK:
+      return UTI_RefidToString(inst->ref_id);
+    default:
+      assert(0);
+  }
+  return NULL;
+}
+
+/* ================================================== */
+
+static void
+mark_ok_sources(SRC_Status status)
+{
+  int i;
+
+  for (i = 0; i < n_sources; i++) {
+    if (sources[i]->status != SRC_OK)
+      continue;
+    sources[i]->status = status;
+  }
+}
+
+/* ================================================== */
+
+static int
+combine_sources(int n_sel_sources, struct timespec *ref_time, double *offset,
+                double *offset_sd, double *frequency, double *skew)
+{
+  struct timespec src_ref_time;
+  double src_offset, src_offset_sd, src_frequency, src_skew;
+  double src_root_delay, src_root_dispersion, sel_src_distance, elapsed;
+  double offset_weight, sum_offset_weight, sum_offset, sum2_offset_sd;
+  double frequency_weight, sum_frequency_weight, sum_frequency, inv_sum2_skew;
+  int i, index, combined;
+
+  if (n_sel_sources == 1)
+    return 1;
+
+  sum_offset_weight = sum_offset = sum2_offset_sd = 0.0;
+  sum_frequency_weight = sum_frequency = inv_sum2_skew = 0.0;
+
+  sel_src_distance = sources[selected_source_index]->sel_info.root_distance;
+  if (sources[selected_source_index]->type == SRC_NTP)
+    sel_src_distance += reselect_distance;
+
+  for (i = combined = 0; i < n_sel_sources; i++) {
+    index = sel_sources[i];
+    SST_GetTrackingData(sources[index]->stats, &src_ref_time,
+                        &src_offset, &src_offset_sd,
+                        &src_frequency, &src_skew,
+                        &src_root_delay, &src_root_dispersion);
+
+    /* Don't include this source if its distance is longer than the distance of
+       the selected source multiplied by the limit, their estimated frequencies
+       are not close, or it was recently marked as distant */
+
+    if (index != selected_source_index &&
+        (sources[index]->sel_info.root_distance > combine_limit * sel_src_distance ||
+         fabs(*frequency - src_frequency) >
+           combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) {
+      /* Use a smaller penalty in first few updates */
+      sources[index]->distant = sources[index]->reachability_size >= SOURCE_REACH_BITS ?
+                                DISTANT_PENALTY : 1;
+    } else if (sources[index]->distant) {
+      sources[index]->distant--;
+    }
+
+    if (sources[index]->distant) {
+      sources[index]->status = SRC_DISTANT;
+      continue;
+    }
+
+    if (sources[index]->status == SRC_OK)
+      sources[index]->status = SRC_UNSELECTED;
+
+    elapsed = UTI_DiffTimespecsToDouble(ref_time, &src_ref_time);
+    src_offset += elapsed * src_frequency;
+    offset_weight = 1.0 / sources[index]->sel_info.root_distance;
+    frequency_weight = 1.0 / src_skew;
+
+    DEBUG_LOG("combining index=%d oweight=%e offset=%e sd=%e fweight=%e freq=%e skew=%e",
+        index, offset_weight, src_offset, src_offset_sd, frequency_weight, src_frequency, src_skew);
+
+    sum_offset_weight += offset_weight;
+    sum_offset += offset_weight * src_offset;
+    sum2_offset_sd += offset_weight * (src_offset_sd * src_offset_sd +
+        (src_offset - *offset) * (src_offset - *offset));
+
+    sum_frequency_weight += frequency_weight;
+    sum_frequency += frequency_weight * src_frequency;
+    inv_sum2_skew += 1.0 / (src_skew * src_skew);
+
+    combined++;
+  }
+
+  assert(combined);
+  *offset = sum_offset / sum_offset_weight;
+  *offset_sd = sqrt(sum2_offset_sd / sum_offset_weight);
+  *frequency = sum_frequency / sum_frequency_weight;
+  *skew = 1.0 / sqrt(inv_sum2_skew);
+
+  DEBUG_LOG("combined result offset=%e sd=%e freq=%e skew=%e",
+      *offset, *offset_sd, *frequency, *skew);
+
+  return combined;
+}
+
+/* ================================================== */
+/* This function selects the current reference from amongst the pool
+   of sources we are holding and updates the local reference */
+
+void
+SRC_SelectSource(SRC_Instance updated_inst)
+{
+  struct SelectInfo *si;
+  struct timespec now, ref_time;
+  int i, j, j1, j2, index, sel_prefer, n_endpoints, n_sel_sources;
+  int n_badstats_sources, max_sel_reach, max_badstat_reach, sel_req_source;
+  int depth, best_depth, trust_depth, best_trust_depth;
+  int combined, stratum, min_stratum, max_score_index;
+  int orphan_stratum, orphan_source, leap_votes, leap_ins, leap_del;
+  double src_offset, src_offset_sd, src_frequency, src_skew;
+  double src_root_delay, src_root_dispersion;
+  double best_lo, best_hi, distance, sel_src_distance, max_score;
+  double first_sample_ago, max_reach_sample_ago;
+  NTP_Leap leap_status;
+
+  if (updated_inst)
+    updated_inst->updates++;
+
+  if (n_sources == 0) {
+    /* In this case, we clearly cannot synchronise to anything */
+    if (selected_source_index != INVALID_SOURCE) {
+      log_selection_message("Can't synchronise: no sources", NULL);
+      selected_source_index = INVALID_SOURCE;
+    }
+    return;
+  }
+
+  /* This is accurate enough and cheaper than calling LCL_ReadCookedTime */
+  SCH_GetLastEventTime(&now, NULL, NULL);
+
+  /* Step 1 - build intervals about each source */
+
+  n_endpoints = 0;
+  n_sel_sources = 0;
+  n_badstats_sources = 0;
+  sel_req_source = 0;
+  max_sel_reach = max_badstat_reach = 0;
+  max_reach_sample_ago = 0.0;
+
+  for (i = 0; i < n_sources; i++) {
+    assert(sources[i]->status != SRC_OK);
+
+    /* If some sources are specified with the require option, at least one
+       of them will have to be selectable in order to update the clock */
+    if (sources[i]->sel_options & SRC_SELECT_REQUIRE)
+      sel_req_source = 1;
+
+    /* Ignore sources which were added with the noselect option */
+    if (sources[i]->sel_options & SRC_SELECT_NOSELECT) {
+      sources[i]->status = SRC_UNSELECTABLE;
+      continue;
+    }
+
+    si = &sources[i]->sel_info;
+    SST_GetSelectionData(sources[i]->stats, &now, &si->stratum,
+                         &si->lo_limit, &si->hi_limit, &si->root_distance,
+                         &si->std_dev, &first_sample_ago,
+                         &si->last_sample_ago, &si->select_ok);
+
+    if (!si->select_ok) {
+      ++n_badstats_sources;
+      sources[i]->status = SRC_BAD_STATS;
+      if (max_badstat_reach < sources[i]->reachability)
+        max_badstat_reach = sources[i]->reachability;
+      continue;
+    }
+
+    /* Include extra dispersion in the root distance of sources that don't
+       have new samples (the last sample is older than span of all samples) */
+    if (first_sample_ago < 2.0 * si->last_sample_ago) {
+      double extra_disp = LCL_GetMaxClockError() *
+                          (2.0 * si->last_sample_ago - first_sample_ago);
+      si->root_distance += extra_disp;
+      si->lo_limit -= extra_disp;
+      si->hi_limit += extra_disp;
+    }
+
+    /* Require the root distance to be below the allowed maximum */
+    if (si->root_distance > max_distance) {
+      sources[i]->status = SRC_BAD_DISTANCE;
+      continue;
+    }
+
+    /* And the same applies for the estimated standard deviation */
+    if (si->std_dev > max_jitter) {
+      sources[i]->status = SRC_JITTERY;
+      continue;
+    }
+
+    sources[i]->status = SRC_OK; /* For now */
+
+    if (sources[i]->reachability && max_reach_sample_ago < first_sample_ago)
+      max_reach_sample_ago = first_sample_ago;
+
+    if (max_sel_reach < sources[i]->reachability)
+      max_sel_reach = sources[i]->reachability;
+  }
+
+  orphan_stratum = REF_GetOrphanStratum();
+  orphan_source = INVALID_SOURCE;
+
+  for (i = 0; i < n_sources; i++) {
+    if (sources[i]->status != SRC_OK)
+      continue;
+
+    si = &sources[i]->sel_info;
+
+    /* Reachability is not a requirement for selection.  An unreachable source
+       can still be selected if its newest sample is not older than the oldest
+       sample from reachable sources. */
+    if (!sources[i]->reachability && max_reach_sample_ago < si->last_sample_ago) {
+      sources[i]->status = SRC_STALE;
+      continue;
+    }
+
+    /* When the local reference is configured with the orphan option, NTP
+       sources that have stratum equal to the configured local stratum are
+       considered to be orphans (i.e. serving local time while not being
+       synchronised with real time) and are excluded from the normal source
+       selection.  Sources with stratum larger than the local stratum are
+       considered to be directly on indirectly synchronised to an orphan and
+       are always ignored.
+
+       If no selectable source is available and all orphan sources have
+       reference IDs larger than the local ID, no source will be selected and
+       the local reference mode will be activated at some point, i.e. this host
+       will become an orphan.  Otherwise, the orphan source with the smallest
+       reference ID will be selected.  This ensures a group of servers polling
+       each other (with the same orphan configuration) which have no external
+       source can settle down to a state where only one server is serving its
+       local unsychronised time and others are synchronised to it. */
+
+    if (si->stratum >= orphan_stratum && sources[i]->type == SRC_NTP) {
+      sources[i]->status = SRC_ORPHAN;
+
+      if (si->stratum == orphan_stratum && sources[i]->reachability &&
+          (orphan_source == INVALID_SOURCE ||
+           sources[i]->ref_id < sources[orphan_source]->ref_id))
+        orphan_source = i;
+
+      continue;
+    }
+
+    ++n_sel_sources;
+  }
+
+  /* If no selectable source is available, consider the orphan source */
+  if (!n_sel_sources && orphan_source != INVALID_SOURCE) {
+    uint32_t local_ref_id = NSR_GetLocalRefid(sources[orphan_source]->ip_addr);
+
+    if (!local_ref_id) {
+      LOG(LOGS_ERR, "Unknown local refid in orphan mode");
+    } else if (sources[orphan_source]->ref_id < local_ref_id) {
+      sources[orphan_source]->status = SRC_OK;
+      n_sel_sources = 1;
+      DEBUG_LOG("selecting orphan refid=%"PRIx32, sources[orphan_source]->ref_id);
+    }
+  }
+
+  for (i = 0; i < n_sources; i++) {
+    if (sources[i]->status != SRC_OK)
+      continue;
+
+    si = &sources[i]->sel_info;
+
+    j1 = n_endpoints;
+    j2 = j1 + 1;
+
+    sort_list[j1].index = i;
+    sort_list[j1].offset = si->lo_limit;
+    sort_list[j1].tag = LOW;
+
+    sort_list[j2].index = i;
+    sort_list[j2].offset = si->hi_limit;
+    sort_list[j2].tag = HIGH;
+
+    n_endpoints += 2;
+  }
+
+  DEBUG_LOG("badstat=%d sel=%d badstat_reach=%x sel_reach=%x max_reach_ago=%f",
+            n_badstats_sources, n_sel_sources, max_badstat_reach,
+            max_sel_reach, max_reach_sample_ago);
+
+  /* Wait for the next call if we have no source selected and there is
+     a source with bad stats (has less than 3 samples) with reachability
+     equal to shifted maximum reachability of sources with valid stats.
+     This delays selecting source on start with servers using the same
+     polling interval until they all have valid stats. */
+  if (n_badstats_sources && n_sel_sources &&
+      selected_source_index == INVALID_SOURCE &&
+      max_sel_reach >> 1 == max_badstat_reach) {
+    mark_ok_sources(SRC_WAITS_STATS);
+    return;
+  }
+
+  if (n_endpoints == 0) {
+    /* No sources provided valid endpoints */
+    if (selected_source_index != INVALID_SOURCE) {
+      log_selection_message("Can't synchronise: no selectable sources", NULL);
+      selected_source_index = INVALID_SOURCE;
+    }
+    return;
+  }
+
+  /* Now sort the endpoint list */
+  qsort((void *) sort_list, n_endpoints, sizeof(struct Sort_Element), compare_sort_elements);
+
+  /* Now search for the interval which is contained in the most
+     individual source intervals.  Any source which overlaps this
+     will be a candidate.
+
+     If we get a case like
+
+     <----------------------->
+         <-->
+                  <-->
+         <===========>
+
+     we will build the interval as shown with '=', whereas with an extra source we get
+
+     <----------------------->
+        <------->
+         <-->
+                  <-->
+         <==>
+
+     The first case is just bad luck - we need extra sources to
+     detect the falseticker, so just make an arbitrary choice based
+     on stratum & stability etc.
+
+     Intervals from sources specified with the trust option have higher
+     priority in the search.
+     */
+
+  trust_depth = best_trust_depth = 0;
+  depth = best_depth = 0;
+  best_lo = best_hi = 0.0;
+
+  for (i = 0; i < n_endpoints; i++) {
+    switch (sort_list[i].tag) {
+      case LOW:
+        depth++;
+        if (sources[sort_list[i].index]->sel_options & SRC_SELECT_TRUST)
+          trust_depth++;
+        if (trust_depth > best_trust_depth ||
+            (trust_depth == best_trust_depth && depth > best_depth)) {
+          best_trust_depth = trust_depth;
+          best_depth = depth;
+          best_lo = sort_list[i].offset;
+        }
+        break;
+      case HIGH:
+        if (trust_depth == best_trust_depth && depth == best_depth)
+          best_hi = sort_list[i].offset;
+        if (sources[sort_list[i].index]->sel_options & SRC_SELECT_TRUST)
+          trust_depth--;
+        depth--;
+        break;
+      default:
+        assert(0);
+    }
+  }
+
+  if (best_depth <= n_sel_sources / 2 && !best_trust_depth) {
+    /* Could not even get half the reachable sources to agree and there
+       are no trusted sources - clearly we can't synchronise */
+
+    if (selected_source_index != INVALID_SOURCE) {
+      log_selection_message("Can't synchronise: no majority", NULL);
+      REF_SetUnsynchronised();
+      selected_source_index = INVALID_SOURCE;
+    }
+
+    /* .. and mark all sources as falsetickers (so they appear thus
+       on the outputs from the command client) */
+    mark_ok_sources(SRC_FALSETICKER);
+
+    return;
+  }
+
+  /* We have our interval, now work out which source are in it,
+     i.e. build list of admissible sources. */
+
+  n_sel_sources = 0;
+
+  for (i = 0; i < n_sources; i++) {
+    /* This should be the same condition to get into the endpoint
+       list */
+    if (sources[i]->status != SRC_OK)
+      continue;
+
+    /* Check if source's interval contains the best interval, or is wholly
+       contained within it.  If there are any trusted sources the first
+       condition is applied only to them to not allow non-trusted sources to
+       move the final offset outside the interval. */
+    if (((!best_trust_depth || sources[i]->sel_options & SRC_SELECT_TRUST) &&
+         sources[i]->sel_info.lo_limit <= best_lo &&
+         sources[i]->sel_info.hi_limit >= best_hi) ||
+        (sources[i]->sel_info.lo_limit >= best_lo &&
+         sources[i]->sel_info.hi_limit <= best_hi)) {
+
+      sel_sources[n_sel_sources++] = i;
+
+      if (sources[i]->sel_options & SRC_SELECT_REQUIRE)
+        sel_req_source = 0;
+    } else if (sources[i]->sel_info.lo_limit <= best_lo &&
+               sources[i]->sel_info.hi_limit >= best_hi) {
+      sources[i]->status = SRC_UNTRUSTED;
+    } else {
+      sources[i]->status = SRC_FALSETICKER;
+    }
+  }
+
+  if (!n_sel_sources || sel_req_source || n_sel_sources < CNF_GetMinSources()) {
+    if (selected_source_index != INVALID_SOURCE) {
+      log_selection_message("Can't synchronise: %s selectable sources",
+                            !n_sel_sources ? "no" :
+                            sel_req_source ? "no required source in" : "not enough");
+      selected_source_index = INVALID_SOURCE;
+    }
+    mark_ok_sources(SRC_WAITS_SOURCES);
+    return;
+  }
+
+  /* Accept leap second status if more than half of selectable (and trusted
+     if there are any) sources agree */
+  for (i = leap_ins = leap_del = leap_votes = 0; i < n_sel_sources; i++) {
+    index = sel_sources[i];
+    if (best_trust_depth && !(sources[index]->sel_options & SRC_SELECT_TRUST))
+      continue;
+    leap_votes++;
+    if (sources[index]->leap_status == LEAP_InsertSecond)
+      leap_ins++;
+    else if (sources[index]->leap_status == LEAP_DeleteSecond)
+      leap_del++;
+  }
+
+  if (leap_ins > leap_votes / 2)
+    leap_status = LEAP_InsertSecond;
+  else if (leap_del > leap_votes / 2)
+    leap_status = LEAP_DeleteSecond;
+  else
+    leap_status = LEAP_Normal;
+
+  /* If there are any sources with prefer option, reduce the list again
+     only to the preferred sources */
+  for (i = 0; i < n_sel_sources; i++) {
+    if (sources[sel_sources[i]]->sel_options & SRC_SELECT_PREFER)
+      break;
+  }
+  if (i < n_sel_sources) {
+    for (i = j = 0; i < n_sel_sources; i++) {
+      if (!(sources[sel_sources[i]]->sel_options & SRC_SELECT_PREFER))
+        sources[sel_sources[i]]->status = SRC_NONPREFERRED;
+      else
+        sel_sources[j++] = sel_sources[i];
+    }
+    assert(j > 0);
+    n_sel_sources = j;
+    sel_prefer = 1;
+  } else {
+    sel_prefer = 0;
+  }
+
+  /* Find minimum stratum */
+
+  index = sel_sources[0];
+  min_stratum = sources[index]->sel_info.stratum;
+  for (i = 1; i < n_sel_sources; i++) {
+    index = sel_sources[i];
+    stratum = sources[index]->sel_info.stratum;
+    if (stratum < min_stratum)
+      min_stratum = stratum;
+  }
+
+  /* Update scores and find the source with maximum score */
+
+  max_score_index = INVALID_SOURCE;
+  max_score = 0.0;
+  sel_src_distance = 0.0;
+
+  if (selected_source_index != INVALID_SOURCE)
+    sel_src_distance = sources[selected_source_index]->sel_info.root_distance +
+      (sources[selected_source_index]->sel_info.stratum - min_stratum) * stratum_weight;
+
+  for (i = 0; i < n_sources; i++) {
+    /* Reset score for non-selectable sources */
+    if (sources[i]->status != SRC_OK ||
+        (sel_prefer && !(sources[i]->sel_options & SRC_SELECT_PREFER))) {
+      sources[i]->sel_score = 1.0;
+      sources[i]->distant = DISTANT_PENALTY;
+      continue;
+    }
+
+    distance = sources[i]->sel_info.root_distance +
+      (sources[i]->sel_info.stratum - min_stratum) * stratum_weight;
+    if (sources[i]->type == SRC_NTP)
+      distance += reselect_distance;
+
+    if (selected_source_index != INVALID_SOURCE) {
+      /* Update score, but only for source pairs where one source
+         has a new sample */
+      if (sources[i] == updated_inst ||
+          sources[selected_source_index] == updated_inst) {
+
+        sources[i]->sel_score *= sel_src_distance / distance;
+
+        if (sources[i]->sel_score < 1.0)
+          sources[i]->sel_score = 1.0;
+      }
+    } else {
+      /* When there is no selected source yet, assign scores so that the
+         source with minimum distance will have maximum score.  The scores
+         will be reset when the source is selected later in this function. */
+      sources[i]->sel_score = 1.0 / distance;
+    }
+
+    DEBUG_LOG("select score=%f refid=%"PRIx32" match_refid=%"PRIx32" status=%d dist=%f",
+              sources[i]->sel_score, sources[i]->ref_id,
+              updated_inst ? updated_inst->ref_id : 0,
+              sources[i]->status, distance);
+
+    if (max_score < sources[i]->sel_score) {
+      max_score = sources[i]->sel_score;
+      max_score_index = i;
+    }
+  }
+
+  assert(max_score_index != INVALID_SOURCE);
+
+  /* Is the current source still a survivor and no other source has reached
+     the score limit? */
+  if (selected_source_index == INVALID_SOURCE ||
+      sources[selected_source_index]->status != SRC_OK ||
+      (max_score_index != selected_source_index && max_score > SCORE_LIMIT)) {
+
+    /* Before selecting the new synchronisation source wait until the reference
+       can be updated */
+    if (sources[max_score_index]->updates == 0) {
+      selected_source_index = INVALID_SOURCE;
+      mark_ok_sources(SRC_WAITS_UPDATE);
+      DEBUG_LOG("best source has no updates");
+      return;
+    }
+
+    selected_source_index = max_score_index;
+    log_selection_message("Selected source %s",
+                          source_to_string(sources[selected_source_index]));
+
+    /* New source has been selected, reset all scores */
+    for (i = 0; i < n_sources; i++) {
+      sources[i]->sel_score = 1.0;
+      sources[i]->distant = 0;
+    }
+  }
+
+  sources[selected_source_index]->status = SRC_SELECTED;
+
+  /* Don't update reference when the selected source has no new samples */
+
+  if (sources[selected_source_index]->updates == 0) {
+    /* Mark the remaining sources as last combine_sources() call */
+
+    for (i = 0; i < n_sel_sources; i++) {
+      index = sel_sources[i];
+      if (sources[index]->status == SRC_OK)
+        sources[index]->status = sources[index]->distant ?
+                                 SRC_DISTANT : SRC_UNSELECTED;
+    }
+    return;
+  }
+
+  for (i = 0; i < n_sources; i++)
+    sources[i]->updates = 0;
+
+  /* Now just use the statistics of the selected source combined with
+     the other selectable sources for trimming the local clock */
+
+  SST_GetTrackingData(sources[selected_source_index]->stats, &ref_time,
+                      &src_offset, &src_offset_sd,
+                      &src_frequency, &src_skew,
+                      &src_root_delay, &src_root_dispersion);
+
+  combined = combine_sources(n_sel_sources, &ref_time, &src_offset,
+                             &src_offset_sd, &src_frequency, &src_skew);
+
+  REF_SetReference(sources[selected_source_index]->sel_info.stratum,
+                   leap_status, combined,
+                   sources[selected_source_index]->ref_id,
+                   sources[selected_source_index]->ip_addr,
+                   &ref_time, src_offset, src_offset_sd,
+                   src_frequency, src_skew,
+                   src_root_delay, src_root_dispersion);
+}
+
+/* ================================================== */
+/* Force reselecting the best source */
+
+void
+SRC_ReselectSource(void)
+{
+  selected_source_index = INVALID_SOURCE;
+  SRC_SelectSource(NULL);
+}
+
+/* ================================================== */
+
+void
+SRC_SetReselectDistance(double distance)
+{
+  if (reselect_distance != distance) {
+    reselect_distance = distance;
+    LOG(LOGS_INFO, "New reselect distance %f", distance);
+  }
+}
+
+/* ================================================== */
+/* This routine is registered as a callback with the local clock
+   module, to be called whenever the local clock changes frequency or
+   is slewed.  It runs through all the existing source statistics, and
+   adjusts them to make them look as though they were sampled under
+   the new regime. */
+
+static void
+slew_sources(struct timespec *raw, struct timespec *cooked, double dfreq,
+             double doffset, LCL_ChangeType change_type, void *anything)
+{
+  int i;
+
+  for (i=0; i<n_sources; i++) {
+    if (change_type == LCL_ChangeUnknownStep) {
+      SST_ResetInstance(sources[i]->stats);
+    } else {
+      SST_SlewSamples(sources[i]->stats, cooked, dfreq, doffset);
+    }
+  }
+
+  if (change_type == LCL_ChangeUnknownStep) {
+    /* After resetting no source is selectable, set reference unsynchronised */
+    SRC_SelectSource(NULL);
+  }
+}
+
+/* ================================================== */
+/* This routine is called when an indeterminate offset is introduced
+   into the local time. */
+
+static void
+add_dispersion(double dispersion, void *anything)
+{
+  int i;
+
+  for (i = 0; i < n_sources; i++) {
+    SST_AddDispersion(sources[i]->stats, dispersion);
+  }
+}
+
+/* ================================================== */
+
+static
+FILE *open_dumpfile(SRC_Instance inst, const char *mode)
+{
+  FILE *f;
+  char filename[1024], *dumpdir;
+
+  dumpdir = CNF_GetDumpDir();
+  if (dumpdir[0] == '\0') {
+    LOG(LOGS_WARN, "dumpdir not specified");
+    return NULL;
+  }
+
+  /* Include IP address in the name for NTP sources, or reference ID in hex */
+  if ((inst->type == SRC_NTP &&
+       snprintf(filename, sizeof (filename), "%s/%s.dat", dumpdir,
+                source_to_string(inst)) >= sizeof (filename)) ||
+      (inst->type != SRC_NTP &&
+       snprintf(filename, sizeof (filename), "%s/refid:%08"PRIx32".dat",
+                dumpdir, inst->ref_id) >= sizeof (filename))) {
+    LOG(LOGS_WARN, "dumpdir too long");
+    return NULL;
+  }
+
+  f = fopen(filename, mode);
+  if (!f && mode[0] != 'r')
+    LOG(LOGS_WARN, "Could not open dump file for %s",
+        source_to_string(inst));
+
+  return f;
+}
+
+/* ================================================== */
+/* This is called to dump out the source measurement registers */
+
+void
+SRC_DumpSources(void)
+{
+  FILE *out;
+  int i;
+
+  for (i = 0; i < n_sources; i++) {
+    out = open_dumpfile(sources[i], "w");
+    if (!out)
+      continue;
+    SST_SaveToFile(sources[i]->stats, out);
+    fclose(out);
+  }
+}
+
+/* ================================================== */
+
+void
+SRC_ReloadSources(void)
+{
+  FILE *in;
+  int i;
+
+  for (i = 0; i < n_sources; i++) {
+    in = open_dumpfile(sources[i], "r");
+    if (!in)
+      continue;
+    if (!SST_LoadFromFile(sources[i]->stats, in))
+      LOG(LOGS_WARN, "Could not load dump file for %s",
+          source_to_string(sources[i]));
+    else
+      LOG(LOGS_INFO, "Loaded dump file for %s",
+          source_to_string(sources[i]));
+    fclose(in);
+  }
+}
+
+/* ================================================== */
+
+void
+SRC_RemoveDumpFiles(void)
+{
+  char pattern[1024], name[64], *dumpdir, *s;
+  IPAddr ip_addr;
+  glob_t gl;
+  size_t i;
+
+  dumpdir = CNF_GetDumpDir();
+  if (dumpdir[0] == '\0' ||
+      snprintf(pattern, sizeof (pattern), "%s/*.dat", dumpdir) >= sizeof (pattern))
+    return;
+
+  if (glob(pattern, 0, NULL, &gl))
+    return;
+
+  for (i = 0; i < gl.gl_pathc; i++) {
+    s = strrchr(gl.gl_pathv[i], '/');
+    if (!s || snprintf(name, sizeof (name), "%s", s + 1) >= sizeof (name))
+      continue;
+
+    /* Remove .dat extension */
+    if (strlen(name) < 4)
+      continue;
+    name[strlen(name) - 4] = '\0';
+
+    /* Check if it looks like name of an actual dump file */
+    if (strncmp(name, "refid:", 6) && !UTI_StringToIP(name, &ip_addr))
+      continue;
+
+    DEBUG_LOG("Removing %s", gl.gl_pathv[i]);
+    unlink(gl.gl_pathv[i]);
+  }
+
+  globfree(&gl);
+}
+
+/* ================================================== */
+
+int
+SRC_IsSyncPeer(SRC_Instance inst)
+{
+  if (inst->index == selected_source_index) {
+    return 1;
+  } else {
+    return 0;
+  }
+
+}
+
+/* ================================================== */
+
+int
+SRC_IsReachable(SRC_Instance inst)
+{
+  return inst->reachability != 0;
+}
+
+/* ================================================== */
+
+int
+SRC_ReadNumberOfSources(void)
+{
+  return n_sources;
+}
+
+/* ================================================== */
+
+int
+SRC_ActiveSources(void)
+{
+  int i, r;
+
+  for (i = r = 0; i < n_sources; i++)
+    if (sources[i]->active)
+      r++;
+
+  return r;
+}
+
+/* ================================================== */
+
+int
+SRC_ReportSource(int index, RPT_SourceReport *report, struct timespec *now)
+{
+  SRC_Instance src;
+  if ((index >= n_sources) || (index < 0)) {
+    return 0;
+  } else {
+    src = sources[index];
+
+    if (src->ip_addr)
+      report->ip_addr = *src->ip_addr;
+    else {
+      /* Use refid as an address */
+      report->ip_addr.addr.in4 = src->ref_id;
+      report->ip_addr.family = IPADDR_INET4;
+    }
+
+    switch (src->status) {
+      case SRC_FALSETICKER:
+        report->state = RPT_FALSETICKER;
+        break;
+      case SRC_JITTERY:
+        report->state = RPT_JITTERY;
+        break;
+      case SRC_UNTRUSTED:
+      case SRC_WAITS_SOURCES:
+      case SRC_NONPREFERRED:
+      case SRC_WAITS_UPDATE:
+      case SRC_DISTANT:
+      case SRC_OUTLIER:
+        report->state = RPT_OUTLIER;
+        break;
+      case SRC_UNSELECTED:
+        report->state = RPT_CANDIDATE;
+        break;
+      case SRC_SELECTED:
+        report->state = RPT_SYNC;
+        break;
+      default:
+        report->state = RPT_UNREACH;
+        break;
+    }
+
+    report->sel_options = src->sel_options;
+    report->reachability = src->reachability;
+
+    /* Call stats module to fill out estimates */
+    SST_DoSourceReport(src->stats, report, now);
+
+    return 1;
+  }
+
+}
+
+/* ================================================== */
+
+int
+SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report, struct timespec *now)
+{ 
+  SRC_Instance src;
+
+  if ((index >= n_sources) || (index < 0)) {
+    return 0;
+  } else {
+    src = sources[index];
+    report->ref_id = src->ref_id;
+    if (src->ip_addr)
+      report->ip_addr = *src->ip_addr;
+    else
+      report->ip_addr.family = IPADDR_UNSPEC; 
+    SST_DoSourcestatsReport(src->stats, report, now);
+    return 1;
+  }
+}
+
+/* ================================================== */
+
+SRC_Type
+SRC_GetType(int index)
+{
+  if ((index >= n_sources) || (index < 0))
+    return -1;
+  return sources[index]->type;
+}
+
+/* ================================================== */
diff --git a/chrony_3_3/sources.h b/chrony_3_3/sources.h
new file mode 100644
index 0000000..60d28fd
--- /dev/null
+++ b/chrony_3_3/sources.h
@@ -0,0 +1,153 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2002
+ * 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  This is the header for the module that manages the collection of all
+  sources that we are making measurements from.  This include all NTP
+  servers & peers, locally connected reference sources, eye/wristwatch
+  drivers etc */
+
+#ifndef GOT_SOURCES_H
+#define GOT_SOURCES_H
+
+#include "sysincl.h"
+
+#include "ntp.h"
+#include "reports.h"
+#include "sourcestats.h"
+
+/* Size of the source reachability register */
+#define SOURCE_REACH_BITS 8
+
+/* This datatype is used to hold information about sources.  The
+   instance must be passed when calling many of the interface
+   functions */
+
+typedef struct SRC_Instance_Record *SRC_Instance;
+
+/* Initialisation function */
+extern void SRC_Initialise(void);
+
+/* Finalisation function */
+extern void SRC_Finalise(void);
+
+typedef enum {
+  SRC_NTP,                      /* NTP client/peer */
+  SRC_REFCLOCK                  /* Rerefence clock */
+} SRC_Type;
+
+/* Function to create a new instance.  This would be called by one of
+   the individual source-type instance creation routines. */
+
+extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options,
+                                          IPAddr *addr, int min_samples, int max_samples,
+                                          double min_delay, double asymmetry);
+
+/* Function to get rid of a source when it is being unconfigured.
+   This may cause the current reference source to be reselected, if this
+   was the reference source or contributed significantly to a
+   falseticker decision. */
+
+extern void SRC_DestroyInstance(SRC_Instance instance);
+
+/* Function to reset a source */
+extern void SRC_ResetInstance(SRC_Instance instance);
+
+/* Function to change the sources's reference ID and IP address */
+extern void SRC_SetRefid(SRC_Instance instance, uint32_t ref_id, IPAddr *addr);
+
+/* Function to get access to the sourcestats instance */
+extern SST_Stats SRC_GetSourcestats(SRC_Instance instance);
+
+/* This function is called by one of the source drivers when it has
+   a new sample that is to be accumulated.
+
+   This function causes the frequency estimation to be re-run for the
+   designated source, and the clock selection procedure to be re-run
+   afterwards.
+
+   sample_time is the local time at which the sample is to be
+   considered to have been made, in terms of doing a regression fit of
+   offset against local time.
+
+   offset is the offset at the time, in seconds.  Positive indicates
+   that the local clock is SLOW relative to the source, negative
+   indicates that the local clock is FAST relative to it.
+
+   root_delay and root_dispersion are in seconds, and are as per
+   RFC 5905.  root_dispersion only includes the peer's root dispersion
+   + local sampling precision + skew dispersion accrued during the
+   measurement.  It is the job of the source statistics algorithms +
+   track.c to add on the extra dispersion due to the residual standard
+   deviation of the offsets from this source after regression, to form
+   the root_dispersion field in the packets transmitted to clients or
+   peers.
+
+   stratum is the stratum of the source that supplied the sample.
+
+   */
+
+extern void SRC_AccumulateSample(SRC_Instance instance, struct timespec *sample_time, double offset, double peer_delay, double peer_dispersion, double root_delay, double root_dispersion, int stratum, NTP_Leap leap_status);
+
+/* This routine sets the source as receiving reachability updates */
+extern void SRC_SetActive(SRC_Instance inst);
+
+/* This routine sets the source as not receiving reachability updates */
+extern void SRC_UnsetActive(SRC_Instance inst);
+
+/* This routine updates the reachability register */
+extern void SRC_UpdateReachability(SRC_Instance inst, int reachable);
+
+/* This routine marks the source unreachable */
+extern void SRC_ResetReachability(SRC_Instance inst);
+
+/* This routine is used to select the best source from amongst those
+   we currently have valid data on, and use it as the tracking base
+   for the local time.  Updates are made to the local reference only
+   when the selected source was updated (set as updated_inst) since
+   the last reference update.  This avoids updating the frequency
+   tracking for every sample from other sources - only the ones from
+   the selected reference make a difference. */
+extern void SRC_SelectSource(SRC_Instance updated_inst);
+
+/* Force reselecting the best source */
+extern void SRC_ReselectSource(void);
+
+/* Set reselect distance */
+extern void SRC_SetReselectDistance(double distance);
+
+extern void SRC_DumpSources(void);
+extern void SRC_ReloadSources(void);
+extern void SRC_RemoveDumpFiles(void);
+
+extern int SRC_IsSyncPeer(SRC_Instance inst);
+extern int SRC_IsReachable(SRC_Instance inst);
+extern int SRC_ReadNumberOfSources(void);
+extern int SRC_ActiveSources(void);
+extern int SRC_ReportSource(int index, RPT_SourceReport *report, struct timespec *now);
+
+extern int SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report, struct timespec *now);
+
+extern SRC_Type SRC_GetType(int index);
+
+#endif /* GOT_SOURCES_H */
diff --git a/chrony_3_3/sourcestats.c b/chrony_3_3/sourcestats.c
new file mode 100644
index 0000000..ff4c652
--- /dev/null
+++ b/chrony_3_3/sourcestats.c
@@ -0,0 +1,1034 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2011-2014, 2016-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 file contains the routines that do the statistical
+  analysis on the samples obtained from the sources,
+  to determined frequencies and error bounds. */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "sourcestats.h"
+#include "memory.h"
+#include "regress.h"
+#include "util.h"
+#include "conf.h"
+#include "logging.h"
+#include "local.h"
+
+/* ================================================== */
+/* Define the maxumum number of samples that we want
+   to store per source */
+#define MAX_SAMPLES 64
+
+/* This is the assumed worst case bound on an unknown frequency,
+   2000ppm, which would be pretty bad */
+#define WORST_CASE_FREQ_BOUND (2000.0/1.0e6)
+
+/* The minimum and maximum assumed skew */
+#define MIN_SKEW 1.0e-12
+#define MAX_SKEW 1.0e+02
+
+/* The minimum standard deviation */
+#define MIN_STDDEV 1.0e-9
+
+/* The asymmetry of network jitter when all jitter is in one direction */
+#define MAX_ASYMMETRY 0.5
+
+/* The minimum estimated asymmetry that can activate the offset correction */
+#define MIN_ASYMMETRY 0.45
+
+/* The minimum number of consecutive asymmetries with the same sign needed
+   to activate the offset correction */
+#define MIN_ASYMMETRY_RUN 10
+
+/* The maximum value of the counter */
+#define MAX_ASYMMETRY_RUN 1000
+
+/* ================================================== */
+
+static LOG_FileID logfileid;
+
+/* ================================================== */
+/* This data structure is used to hold the history of data from the
+   source */
+
+struct SST_Stats_Record {
+
+  /* Reference ID and IP address of source, used for logging to statistics log */
+  uint32_t refid;
+  IPAddr *ip_addr;
+
+  /* User defined minimum and maximum number of samples */
+  int min_samples;
+  int max_samples;
+
+  /* User defined minimum delay */
+  double fixed_min_delay;
+
+  /* User defined asymmetry of network jitter */
+  double fixed_asymmetry;
+
+  /* Number of samples currently stored.  The samples are stored in circular
+     buffer. */
+  int n_samples;
+
+  /* Number of extra samples stored in sample_times, offsets and peer_delays
+     arrays that are used to extend the runs test */
+  int runs_samples;
+
+  /* The index of the newest sample */
+  int last_sample;
+
+  /* Flag indicating whether last regression was successful */
+  int regression_ok;
+
+  /* The best individual sample that we are holding, in terms of the minimum
+     root distance at the present time */
+  int best_single_sample;
+
+  /* The index of the sample with minimum delay in peer_delays */
+  int min_delay_sample;
+
+  /* This is the estimated offset (+ve => local fast) at a particular time */
+  double estimated_offset;
+  double estimated_offset_sd;
+  struct timespec offset_time;
+
+  /* Number of runs of the same sign amongst the residuals */
+  int nruns;
+
+  /* Number of consecutive estimated asymmetries with the same sign.
+     The sign of the number encodes the sign of the asymmetry. */
+  int asymmetry_run;
+
+  /* This is the latest estimated asymmetry of network jitter */
+  double asymmetry;
+
+  /* This value contains the estimated frequency.  This is the number
+     of seconds that the local clock gains relative to the reference
+     source per unit local time.  (Positive => local clock fast,
+     negative => local clock slow) */
+  double estimated_frequency;
+
+  /* This is the assumed worst case bounds on the estimated frequency.
+     We assume that the true frequency lies within +/- half this much
+     about estimated_frequency */
+  double skew;
+
+  /* This is the estimated standard deviation of the data points */
+  double std_dev;
+
+  /* This array contains the sample epochs, in terms of the local
+     clock. */
+  struct timespec sample_times[MAX_SAMPLES * REGRESS_RUNS_RATIO];
+
+  /* This is an array of offsets, in seconds, corresponding to the
+     sample times.  In this module, we use the convention that
+     positive means the local clock is FAST of the source and negative
+     means it is SLOW.  This is contrary to the convention in the NTP
+     stuff. */
+  double offsets[MAX_SAMPLES * REGRESS_RUNS_RATIO];
+
+  /* This is an array of the offsets as originally measured.  Local
+     clock fast of real time is indicated by positive values.  This
+     array is not slewed to adjust the readings when we apply
+     adjustments to the local clock, as is done for the array
+     'offset'. */
+  double orig_offsets[MAX_SAMPLES];
+
+  /* This is an array of peer delays, in seconds, being the roundtrip
+     measurement delay to the peer */
+  double peer_delays[MAX_SAMPLES * REGRESS_RUNS_RATIO];
+
+  /* This is an array of peer dispersions, being the skew and local
+     precision dispersion terms from sampling the peer */
+  double peer_dispersions[MAX_SAMPLES];
+
+  /* This array contains the root delays of each sample, in seconds */
+  double root_delays[MAX_SAMPLES];
+
+  /* This array contains the root dispersions of each sample at the
+     time of the measurements */
+  double root_dispersions[MAX_SAMPLES];
+
+  /* This array contains the strata that were associated with the sources
+     at the times the samples were generated */
+  int strata[MAX_SAMPLES];
+
+};
+
+/* ================================================== */
+
+static void find_min_delay_sample(SST_Stats inst);
+static int get_buf_index(SST_Stats inst, int i);
+
+/* ================================================== */
+
+void
+SST_Initialise(void)
+{
+  logfileid = CNF_GetLogStatistics() ? LOG_FileOpen("statistics",
+      "   Date (UTC) Time     IP Address    Std dev'n Est offset  Offset sd  Diff freq   Est skew  Stress  Ns  Bs  Nr  Asym")
+    : -1;
+}
+
+/* ================================================== */
+
+void
+SST_Finalise(void)
+{
+}
+
+/* ================================================== */
+/* This function creates a new instance of the statistics handler */
+
+SST_Stats
+SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples,
+                   double min_delay, double asymmetry)
+{
+  SST_Stats inst;
+  inst = MallocNew(struct SST_Stats_Record);
+
+  inst->min_samples = min_samples;
+  inst->max_samples = max_samples;
+  inst->fixed_min_delay = min_delay;
+  inst->fixed_asymmetry = asymmetry;
+
+  SST_SetRefid(inst, refid, addr);
+  SST_ResetInstance(inst);
+
+  return inst;
+}
+
+/* ================================================== */
+/* This function deletes an instance of the statistics handler. */
+
+void
+SST_DeleteInstance(SST_Stats inst)
+{
+  Free(inst);
+}
+
+/* ================================================== */
+
+void
+SST_ResetInstance(SST_Stats inst)
+{
+  inst->n_samples = 0;
+  inst->runs_samples = 0;
+  inst->last_sample = 0;
+  inst->regression_ok = 0;
+  inst->best_single_sample = 0;
+  inst->min_delay_sample = 0;
+  inst->estimated_frequency = 0;
+  inst->skew = 2000.0e-6;
+  inst->estimated_offset = 0.0;
+  inst->estimated_offset_sd = 86400.0; /* Assume it's at least within a day! */
+  UTI_ZeroTimespec(&inst->offset_time);
+  inst->std_dev = 4.0;
+  inst->nruns = 0;
+  inst->asymmetry_run = 0;
+  inst->asymmetry = 0.0;
+}
+
+/* ================================================== */
+
+void
+SST_SetRefid(SST_Stats inst, uint32_t refid, IPAddr *addr)
+{
+  inst->refid = refid;
+  inst->ip_addr = addr;
+}
+
+/* ================================================== */
+/* This function is called to prune the register down when it is full.
+   For now, just discard the oldest sample.  */
+
+static void
+prune_register(SST_Stats inst, int new_oldest)
+{
+  if (!new_oldest)
+    return;
+
+  assert(inst->n_samples >= new_oldest);
+  inst->n_samples -= new_oldest;
+  inst->runs_samples += new_oldest;
+  if (inst->runs_samples > inst->n_samples * (REGRESS_RUNS_RATIO - 1))
+    inst->runs_samples = inst->n_samples * (REGRESS_RUNS_RATIO - 1);
+  
+  assert(inst->n_samples + inst->runs_samples <= MAX_SAMPLES * REGRESS_RUNS_RATIO);
+
+  find_min_delay_sample(inst);
+}
+
+/* ================================================== */
+
+void
+SST_AccumulateSample(SST_Stats inst, struct timespec *sample_time,
+                     double offset,
+                     double peer_delay, double peer_dispersion,
+                     double root_delay, double root_dispersion,
+                     int stratum)
+{
+  int n, m;
+
+  /* Make room for the new sample */
+  if (inst->n_samples > 0 &&
+      (inst->n_samples == MAX_SAMPLES || inst->n_samples == inst->max_samples)) {
+    prune_register(inst, 1);
+  }
+
+  /* Make sure it's newer than the last sample */
+  if (inst->n_samples &&
+      UTI_CompareTimespecs(&inst->sample_times[inst->last_sample], sample_time) >= 0) {
+    LOG(LOGS_WARN, "Out of order sample detected, discarding history for %s",
+        inst->ip_addr ? UTI_IPToString(inst->ip_addr) : UTI_RefidToString(inst->refid));
+    SST_ResetInstance(inst);
+  }
+
+  n = inst->last_sample = (inst->last_sample + 1) %
+    (MAX_SAMPLES * REGRESS_RUNS_RATIO);
+  m = n % MAX_SAMPLES;
+
+  inst->sample_times[n] = *sample_time;
+  inst->offsets[n] = offset;
+  inst->orig_offsets[m] = offset;
+  inst->peer_delays[n] = peer_delay;
+  inst->peer_dispersions[m] = peer_dispersion;
+  inst->root_delays[m] = root_delay;
+  inst->root_dispersions[m] = root_dispersion;
+  inst->strata[m] = stratum;
+ 
+  if (inst->peer_delays[n] < inst->fixed_min_delay)
+    inst->peer_delays[n] = 2.0 * inst->fixed_min_delay - inst->peer_delays[n];
+
+  if (!inst->n_samples || inst->peer_delays[n] < inst->peer_delays[inst->min_delay_sample])
+    inst->min_delay_sample = n;
+
+  ++inst->n_samples;
+}
+
+/* ================================================== */
+/* Return index of the i-th sample in the sample_times and offset buffers,
+   i can be negative down to -runs_samples */
+
+static int
+get_runsbuf_index(SST_Stats inst, int i)
+{
+  return (unsigned int)(inst->last_sample + 2 * MAX_SAMPLES * REGRESS_RUNS_RATIO -
+      inst->n_samples + i + 1) % (MAX_SAMPLES * REGRESS_RUNS_RATIO);
+}
+
+/* ================================================== */
+/* Return index of the i-th sample in the other buffers */
+
+static int
+get_buf_index(SST_Stats inst, int i)
+{
+  return (unsigned int)(inst->last_sample + MAX_SAMPLES * REGRESS_RUNS_RATIO -
+      inst->n_samples + i + 1) % MAX_SAMPLES;
+}
+
+/* ================================================== */
+/* This function is used by both the regression routines to find the
+   time interval between each historical sample and the most recent
+   one */
+
+static void
+convert_to_intervals(SST_Stats inst, double *times_back)
+{
+  struct timespec *ts;
+  int i;
+
+  ts = &inst->sample_times[inst->last_sample];
+  for (i = -inst->runs_samples; i < inst->n_samples; i++) {
+    /* The entries in times_back[] should end up negative */
+    times_back[i] = UTI_DiffTimespecsToDouble(&inst->sample_times[get_runsbuf_index(inst, i)], ts);
+  }
+}
+
+/* ================================================== */
+
+static void
+find_best_sample_index(SST_Stats inst, double *times_back)
+{
+  /* With the value of skew that has been computed, see which of the
+     samples offers the tightest bound on root distance */
+
+  double root_distance, best_root_distance;
+  double elapsed;
+  int i, j, best_index;
+
+  if (!inst->n_samples)
+    return;
+
+  best_index = -1;
+  best_root_distance = DBL_MAX;
+
+  for (i = 0; i < inst->n_samples; i++) {
+    j = get_buf_index(inst, i);
+
+    elapsed = -times_back[i];
+    assert(elapsed >= 0.0);
+
+    root_distance = inst->root_dispersions[j] + elapsed * inst->skew + 0.5 * inst->root_delays[j];
+    if (root_distance < best_root_distance) {
+      best_root_distance = root_distance;
+      best_index = i;
+    }
+  }
+
+  assert(best_index >= 0);
+  inst->best_single_sample = best_index;
+}
+
+/* ================================================== */
+
+static void
+find_min_delay_sample(SST_Stats inst)
+{
+  int i, index;
+
+  inst->min_delay_sample = get_runsbuf_index(inst, -inst->runs_samples);
+
+  for (i = -inst->runs_samples + 1; i < inst->n_samples; i++) {
+    index = get_runsbuf_index(inst, i);
+    if (inst->peer_delays[index] < inst->peer_delays[inst->min_delay_sample])
+      inst->min_delay_sample = index;
+  }
+}
+
+/* ================================================== */
+/* This function estimates asymmetry of network jitter on the path to the
+   source as a slope of offset against network delay in multiple linear
+   regression.  If the asymmetry is significant and its sign doesn't change
+   frequently, the measured offsets (which are used later to estimate the
+   offset and frequency of the clock) are corrected to correspond to the
+   minimum network delay.  This can significantly improve the accuracy and
+   stability of the estimated offset and frequency. */
+
+static int
+estimate_asymmetry(double *times_back, double *offsets, double *delays, int n,
+                   double *asymmetry, int *asymmetry_run)
+{
+  double a;
+
+  /* Reset the counter when the regression fails or the sign changes */
+  if (!RGR_MultipleRegress(times_back, delays, offsets, n, &a) ||
+      a * *asymmetry_run < 0.0) {
+    *asymmetry = 0;
+    *asymmetry_run = 0.0;
+    return 0;
+  }
+
+  if (a <= -MIN_ASYMMETRY && *asymmetry_run > -MAX_ASYMMETRY_RUN)
+    (*asymmetry_run)--;
+  else if (a >= MIN_ASYMMETRY && *asymmetry_run < MAX_ASYMMETRY_RUN)
+    (*asymmetry_run)++;
+
+  if (abs(*asymmetry_run) < MIN_ASYMMETRY_RUN)
+    return 0;
+
+  *asymmetry = CLAMP(-MAX_ASYMMETRY, a, MAX_ASYMMETRY);
+
+  return 1;
+}
+
+/* ================================================== */
+
+static void
+correct_asymmetry(SST_Stats inst, double *times_back, double *offsets)
+{
+  double min_delay, delays[MAX_SAMPLES * REGRESS_RUNS_RATIO];
+  int i, n;
+
+  /* Check if the asymmetry was not specified to be zero */
+  if (inst->fixed_asymmetry == 0.0)
+    return;
+
+  min_delay = SST_MinRoundTripDelay(inst);
+  n = inst->runs_samples + inst->n_samples;
+
+  for (i = 0; i < n; i++)
+    delays[i] = inst->peer_delays[get_runsbuf_index(inst, i - inst->runs_samples)] -
+                min_delay;
+
+  if (fabs(inst->fixed_asymmetry) <= MAX_ASYMMETRY) {
+    inst->asymmetry = inst->fixed_asymmetry;
+  } else {
+    if (!estimate_asymmetry(times_back, offsets, delays, n,
+                            &inst->asymmetry, &inst->asymmetry_run))
+      return;
+  }
+
+  /* Correct the offsets */
+  for (i = 0; i < n; i++)
+    offsets[i] -= inst->asymmetry * delays[i];
+}
+
+/* ================================================== */
+
+/* This defines the assumed ratio between the standard deviation of
+   the samples and the peer distance as measured from the round trip
+   time.  E.g. a value of 4 means that we think the standard deviation
+   is four times the fluctuation  of the peer distance */
+
+#define SD_TO_DIST_RATIO 0.7
+
+/* ================================================== */
+/* This function runs the linear regression operation on the data.  It
+   finds the set of most recent samples that give the tightest
+   confidence interval for the frequency, and truncates the register
+   down to that number of samples */
+
+void
+SST_DoNewRegression(SST_Stats inst)
+{
+  double times_back[MAX_SAMPLES * REGRESS_RUNS_RATIO];
+  double offsets[MAX_SAMPLES * REGRESS_RUNS_RATIO];
+  double peer_distances[MAX_SAMPLES];
+  double weights[MAX_SAMPLES];
+
+  int degrees_of_freedom;
+  int best_start, times_back_start;
+  double est_intercept, est_slope, est_var, est_intercept_sd, est_slope_sd;
+  int i, j, nruns;
+  double min_distance, median_distance;
+  double sd_weight, sd;
+  double old_skew, old_freq, stress;
+  double precision;
+
+  convert_to_intervals(inst, times_back + inst->runs_samples);
+
+  if (inst->n_samples > 0) {
+    for (i = -inst->runs_samples; i < inst->n_samples; i++) {
+      offsets[i + inst->runs_samples] = inst->offsets[get_runsbuf_index(inst, i)];
+    }
+  
+    for (i = 0, min_distance = DBL_MAX; i < inst->n_samples; i++) {
+      j = get_buf_index(inst, i);
+      peer_distances[i] = 0.5 * inst->peer_delays[get_runsbuf_index(inst, i)] +
+                          inst->peer_dispersions[j];
+      if (peer_distances[i] < min_distance) {
+        min_distance = peer_distances[i];
+      }
+    }
+
+    /* And now, work out the weight vector */
+
+    precision = LCL_GetSysPrecisionAsQuantum();
+    median_distance = RGR_FindMedian(peer_distances, inst->n_samples);
+
+    sd = (median_distance - min_distance) / SD_TO_DIST_RATIO;
+    sd = CLAMP(precision, sd, min_distance);
+    min_distance += precision;
+
+    for (i=0; i<inst->n_samples; i++) {
+      sd_weight = 1.0;
+      if (peer_distances[i] > min_distance)
+        sd_weight += (peer_distances[i] - min_distance) / sd;
+      weights[i] = sd_weight * sd_weight;
+    }
+  }
+
+  correct_asymmetry(inst, times_back, offsets);
+
+  inst->regression_ok = RGR_FindBestRegression(times_back + inst->runs_samples,
+                                         offsets + inst->runs_samples, weights,
+                                         inst->n_samples, inst->runs_samples,
+                                         inst->min_samples,
+                                         &est_intercept, &est_slope, &est_var,
+                                         &est_intercept_sd, &est_slope_sd,
+                                         &best_start, &nruns, &degrees_of_freedom);
+
+  if (inst->regression_ok) {
+
+    old_skew = inst->skew;
+    old_freq = inst->estimated_frequency;
+  
+    inst->estimated_frequency = est_slope;
+    inst->skew = est_slope_sd * RGR_GetTCoef(degrees_of_freedom);
+    inst->estimated_offset = est_intercept;
+    inst->offset_time = inst->sample_times[inst->last_sample];
+    inst->estimated_offset_sd = est_intercept_sd;
+    inst->std_dev = MAX(MIN_STDDEV, sqrt(est_var));
+    inst->nruns = nruns;
+
+    inst->skew = CLAMP(MIN_SKEW, inst->skew, MAX_SKEW);
+    stress = fabs(old_freq - inst->estimated_frequency) / old_skew;
+
+    DEBUG_LOG("off=%e freq=%e skew=%e n=%d bs=%d runs=%d asym=%f arun=%d",
+              inst->estimated_offset, inst->estimated_frequency, inst->skew,
+              inst->n_samples, best_start, inst->nruns,
+              inst->asymmetry, inst->asymmetry_run);
+
+    if (logfileid != -1) {
+      LOG_FileWrite(logfileid, "%s %-15s %10.3e %10.3e %10.3e %10.3e %10.3e %7.1e %3d %3d %3d %5.2f",
+              UTI_TimeToLogForm(inst->offset_time.tv_sec),
+              inst->ip_addr ? UTI_IPToString(inst->ip_addr) : UTI_RefidToString(inst->refid),
+              inst->std_dev,
+              inst->estimated_offset, inst->estimated_offset_sd,
+              inst->estimated_frequency, inst->skew, stress,
+              inst->n_samples, best_start, inst->nruns,
+              inst->asymmetry);
+    }
+
+    times_back_start = inst->runs_samples + best_start;
+    prune_register(inst, best_start);
+  } else {
+    inst->estimated_frequency = 0.0;
+    inst->skew = WORST_CASE_FREQ_BOUND;
+    times_back_start = 0;
+  }
+
+  find_best_sample_index(inst, times_back + times_back_start);
+
+}
+
+/* ================================================== */
+/* Return the assumed worst case range of values that this source's
+   frequency lies within.  Frequency is defined as the amount of time
+   the local clock gains relative to the source per unit local clock
+   time. */
+void
+SST_GetFrequencyRange(SST_Stats inst,
+                      double *lo, double *hi)
+{
+  double freq, skew;
+  freq = inst->estimated_frequency;
+  skew = inst->skew;
+  *lo = freq - skew;
+  *hi = freq + skew;
+
+  /* This function is currently used only to determine the values of delta
+     and epsilon in the ntp_core module. Limit the skew to a reasonable maximum
+     to avoid failing the dispersion test too easily. */
+  if (skew > WORST_CASE_FREQ_BOUND) {
+    *lo = -WORST_CASE_FREQ_BOUND;
+    *hi = WORST_CASE_FREQ_BOUND;
+  }
+}
+
+/* ================================================== */
+
+void
+SST_GetSelectionData(SST_Stats inst, struct timespec *now,
+                     int *stratum,
+                     double *offset_lo_limit,
+                     double *offset_hi_limit,
+                     double *root_distance,
+                     double *std_dev,
+                     double *first_sample_ago,
+                     double *last_sample_ago,
+                     int *select_ok)
+{
+  double offset, sample_elapsed;
+  int i, j;
+  
+  if (!inst->n_samples) {
+    *select_ok = 0;
+    return;
+  }
+
+  i = get_runsbuf_index(inst, inst->best_single_sample);
+  j = get_buf_index(inst, inst->best_single_sample);
+
+  *stratum = inst->strata[get_buf_index(inst, inst->n_samples - 1)];
+  *std_dev = inst->std_dev;
+
+  sample_elapsed = fabs(UTI_DiffTimespecsToDouble(now, &inst->sample_times[i]));
+  offset = inst->offsets[i] + sample_elapsed * inst->estimated_frequency;
+  *root_distance = 0.5 * inst->root_delays[j] +
+    inst->root_dispersions[j] + sample_elapsed * inst->skew;
+
+  *offset_lo_limit = offset - *root_distance;
+  *offset_hi_limit = offset + *root_distance;
+
+#if 0
+  double average_offset, elapsed;
+  int average_ok;
+  /* average_ok ignored for now */
+  elapsed = UTI_DiffTimespecsToDouble(now, &inst->offset_time);
+  average_offset = inst->estimated_offset + inst->estimated_frequency * elapsed;
+  if (fabs(average_offset - offset) <=
+      inst->peer_dispersions[j] + 0.5 * inst->peer_delays[i]) {
+    average_ok = 1;
+  } else {
+    average_ok = 0;
+  }
+#endif
+
+  i = get_runsbuf_index(inst, 0);
+  *first_sample_ago = UTI_DiffTimespecsToDouble(now, &inst->sample_times[i]);
+  i = get_runsbuf_index(inst, inst->n_samples - 1);
+  *last_sample_ago = UTI_DiffTimespecsToDouble(now, &inst->sample_times[i]);
+
+  *select_ok = inst->regression_ok;
+
+  DEBUG_LOG("n=%d off=%f dist=%f sd=%f first_ago=%f last_ago=%f selok=%d",
+            inst->n_samples, offset, *root_distance, *std_dev,
+            *first_sample_ago, *last_sample_ago, *select_ok);
+}
+
+/* ================================================== */
+
+void
+SST_GetTrackingData(SST_Stats inst, struct timespec *ref_time,
+                    double *average_offset, double *offset_sd,
+                    double *frequency, double *skew,
+                    double *root_delay, double *root_dispersion)
+{
+  int i, j;
+  double elapsed_sample;
+
+  assert(inst->n_samples > 0);
+
+  i = get_runsbuf_index(inst, inst->best_single_sample);
+  j = get_buf_index(inst, inst->best_single_sample);
+
+  *ref_time = inst->offset_time;
+  *average_offset = inst->estimated_offset;
+  *offset_sd = inst->estimated_offset_sd;
+  *frequency = inst->estimated_frequency;
+  *skew = inst->skew;
+  *root_delay = inst->root_delays[j];
+
+  elapsed_sample = UTI_DiffTimespecsToDouble(&inst->offset_time, &inst->sample_times[i]);
+  *root_dispersion = inst->root_dispersions[j] + inst->skew * elapsed_sample;
+
+  DEBUG_LOG("n=%d freq=%f (%.3fppm) skew=%f (%.3fppm) avoff=%f offsd=%f disp=%f",
+            inst->n_samples, *frequency, 1.0e6* *frequency, *skew, 1.0e6* *skew,
+            *average_offset, *offset_sd, *root_dispersion);
+
+}
+
+/* ================================================== */
+
+void
+SST_SlewSamples(SST_Stats inst, struct timespec *when, double dfreq, double doffset)
+{
+  int m, i;
+  double delta_time;
+  struct timespec *sample, prev;
+  double prev_offset, prev_freq;
+
+  if (!inst->n_samples)
+    return;
+
+  for (m = -inst->runs_samples; m < inst->n_samples; m++) {
+    i = get_runsbuf_index(inst, m);
+    sample = &inst->sample_times[i];
+    prev = *sample;
+    UTI_AdjustTimespec(sample, when, sample, &delta_time, dfreq, doffset);
+    inst->offsets[i] += delta_time;
+  }
+
+  /* Update the regression estimates */
+  prev = inst->offset_time;
+  prev_offset = inst->estimated_offset;
+  prev_freq = inst->estimated_frequency;
+  UTI_AdjustTimespec(&inst->offset_time, when, &inst->offset_time,
+      &delta_time, dfreq, doffset);
+  inst->estimated_offset += delta_time;
+  inst->estimated_frequency = (inst->estimated_frequency - dfreq) / (1.0 - dfreq);
+
+  DEBUG_LOG("n=%d m=%d old_off_time=%s new=%s old_off=%f new_off=%f old_freq=%.3f new_freq=%.3f",
+            inst->n_samples, inst->runs_samples,
+            UTI_TimespecToString(&prev), UTI_TimespecToString(&inst->offset_time),
+            prev_offset, inst->estimated_offset,
+            1.0e6 * prev_freq, 1.0e6 * inst->estimated_frequency);
+}
+
+/* ================================================== */
+
+void 
+SST_AddDispersion(SST_Stats inst, double dispersion)
+{
+  int m, i;
+
+  for (m = 0; m < inst->n_samples; m++) {
+    i = get_buf_index(inst, m);
+    inst->root_dispersions[i] += dispersion;
+    inst->peer_dispersions[i] += dispersion;
+  }
+}
+
+/* ================================================== */
+
+double
+SST_PredictOffset(SST_Stats inst, struct timespec *when)
+{
+  double elapsed;
+  
+  if (inst->n_samples < 3) {
+    /* We don't have any useful statistics, and presumably the poll
+       interval is minimal.  We can't do any useful prediction other
+       than use the latest sample or zero if we don't have any samples */
+    if (inst->n_samples > 0) {
+      return inst->offsets[inst->last_sample];
+    } else {
+      return 0.0;
+    }
+  } else {
+    elapsed = UTI_DiffTimespecsToDouble(when, &inst->offset_time);
+    return inst->estimated_offset + elapsed * inst->estimated_frequency;
+  }
+
+}
+
+/* ================================================== */
+
+double
+SST_MinRoundTripDelay(SST_Stats inst)
+{
+  if (inst->fixed_min_delay > 0.0)
+    return inst->fixed_min_delay;
+
+  if (!inst->n_samples)
+    return DBL_MAX;
+
+  return inst->peer_delays[inst->min_delay_sample];
+}
+
+/* ================================================== */
+
+int
+SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
+                     double *last_sample_ago, double *predicted_offset,
+                     double *min_delay, double *skew, double *std_dev)
+{
+  if (inst->n_samples < 6)
+    return 0;
+
+  *last_sample_ago = UTI_DiffTimespecsToDouble(sample_time, &inst->offset_time);
+  *predicted_offset = inst->estimated_offset +
+                      *last_sample_ago * inst->estimated_frequency;
+  *min_delay = SST_MinRoundTripDelay(inst);
+  *skew = inst->skew;
+  *std_dev = inst->std_dev;
+
+  return 1;
+}
+
+/* ================================================== */
+/* This is used to save the register to a file, so that we can reload
+   it after restarting the daemon */
+
+void
+SST_SaveToFile(SST_Stats inst, FILE *out)
+{
+  int m, i, j;
+
+  fprintf(out, "%d\n", inst->n_samples);
+
+  for(m = 0; m < inst->n_samples; m++) {
+    i = get_runsbuf_index(inst, m);
+    j = get_buf_index(inst, m);
+
+    fprintf(out,
+#ifdef HAVE_LONG_TIME_T
+            "%08"PRIx64" %08lx %.6e %.6e %.6e %.6e %.6e %.6e %.6e %d\n",
+            (uint64_t)inst->sample_times[i].tv_sec,
+#else
+            "%08lx %08lx %.6e %.6e %.6e %.6e %.6e %.6e %.6e %d\n",
+            (unsigned long)inst->sample_times[i].tv_sec,
+#endif
+            (unsigned long)inst->sample_times[i].tv_nsec / 1000,
+            inst->offsets[i],
+            inst->orig_offsets[j],
+            inst->peer_delays[i],
+            inst->peer_dispersions[j],
+            inst->root_delays[j],
+            inst->root_dispersions[j],
+            1.0, /* used to be inst->weights[i] */
+            inst->strata[j]);
+
+  }
+
+  fprintf(out, "%d\n", inst->asymmetry_run);
+}
+
+/* ================================================== */
+/* This is used to reload samples from a file */
+
+int
+SST_LoadFromFile(SST_Stats inst, FILE *in)
+{
+#ifdef HAVE_LONG_TIME_T
+  uint64_t sec;
+#else
+  unsigned long sec;
+#endif
+  unsigned long usec;
+  int i;
+  char line[1024];
+  double weight;
+
+  SST_ResetInstance(inst);
+
+  if (fgets(line, sizeof(line), in) &&
+      sscanf(line, "%d", &inst->n_samples) == 1 &&
+      inst->n_samples >= 0 && inst->n_samples <= MAX_SAMPLES) {
+
+    for (i=0; i<inst->n_samples; i++) {
+      if (!fgets(line, sizeof(line), in) ||
+          (sscanf(line,
+#ifdef HAVE_LONG_TIME_T
+                  "%"SCNx64"%lx%lf%lf%lf%lf%lf%lf%lf%d\n",
+#else
+                  "%lx%lx%lf%lf%lf%lf%lf%lf%lf%d\n",
+#endif
+                  &(sec), &(usec),
+                  &(inst->offsets[i]),
+                  &(inst->orig_offsets[i]),
+                  &(inst->peer_delays[i]),
+                  &(inst->peer_dispersions[i]),
+                  &(inst->root_delays[i]),
+                  &(inst->root_dispersions[i]),
+                  &weight, /* not used anymore */
+                  &(inst->strata[i])) != 10)) {
+
+        /* This is the branch taken if the read FAILED */
+
+        inst->n_samples = 0; /* Load abandoned if any sign of corruption */
+        return 0;
+      } else {
+
+        /* This is the branch taken if the read is SUCCESSFUL */
+        inst->sample_times[i].tv_sec = sec;
+        inst->sample_times[i].tv_nsec = 1000 * usec;
+        UTI_NormaliseTimespec(&inst->sample_times[i]);
+      }
+    }
+
+    /* This field was not saved in older versions */
+    if (!fgets(line, sizeof(line), in) || sscanf(line, "%d\n", &inst->asymmetry_run) != 1)
+      inst->asymmetry_run = 0;
+  } else {
+    inst->n_samples = 0; /* Load abandoned if any sign of corruption */
+    return 0;
+  }
+
+  if (!inst->n_samples)
+    return 1;
+
+  inst->last_sample = inst->n_samples - 1;
+
+  find_min_delay_sample(inst);
+  SST_DoNewRegression(inst);
+
+  return 1;
+}
+
+/* ================================================== */
+
+void
+SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timespec *now)
+{
+  int i, j;
+  struct timespec last_sample_time;
+
+  if (inst->n_samples > 0) {
+    i = get_runsbuf_index(inst, inst->n_samples - 1);
+    j = get_buf_index(inst, inst->n_samples - 1);
+    report->orig_latest_meas = inst->orig_offsets[j];
+    report->latest_meas = inst->offsets[i];
+    report->latest_meas_err = 0.5*inst->root_delays[j] + inst->root_dispersions[j];
+    report->stratum = inst->strata[j];
+
+    /* Align the sample time to reduce the leak of the receive timestamp */
+    last_sample_time = inst->sample_times[i];
+    last_sample_time.tv_nsec = 0;
+    report->latest_meas_ago = UTI_DiffTimespecsToDouble(now, &last_sample_time);
+  } else {
+    report->latest_meas_ago = (uint32_t)-1;
+    report->orig_latest_meas = 0;
+    report->latest_meas = 0;
+    report->latest_meas_err = 0;
+    report->stratum = 0;
+  }
+}
+
+/* ================================================== */
+
+int
+SST_Samples(SST_Stats inst)
+{
+  return inst->n_samples;
+}
+
+/* ================================================== */
+
+void
+SST_DoSourcestatsReport(SST_Stats inst, RPT_SourcestatsReport *report, struct timespec *now)
+{
+  double dspan;
+  double elapsed, sample_elapsed;
+  int li, lj, bi, bj;
+
+  report->n_samples = inst->n_samples;
+  report->n_runs = inst->nruns;
+
+  if (inst->n_samples > 1) {
+    li = get_runsbuf_index(inst, inst->n_samples - 1);
+    lj = get_buf_index(inst, inst->n_samples - 1);
+    dspan = UTI_DiffTimespecsToDouble(&inst->sample_times[li],
+        &inst->sample_times[get_runsbuf_index(inst, 0)]);
+    report->span_seconds = (unsigned long) (dspan + 0.5);
+
+    if (inst->n_samples > 3) {
+      elapsed = UTI_DiffTimespecsToDouble(now, &inst->offset_time);
+      bi = get_runsbuf_index(inst, inst->best_single_sample);
+      bj = get_buf_index(inst, inst->best_single_sample);
+      sample_elapsed = UTI_DiffTimespecsToDouble(now, &inst->sample_times[bi]);
+      report->est_offset = inst->estimated_offset + elapsed * inst->estimated_frequency;
+      report->est_offset_err = (inst->estimated_offset_sd +
+                 sample_elapsed * inst->skew +
+                 (0.5*inst->root_delays[bj] + inst->root_dispersions[bj]));
+    } else {
+      report->est_offset = inst->offsets[li];
+      report->est_offset_err = 0.5*inst->root_delays[lj] + inst->root_dispersions[lj];
+    }
+  } else {
+    report->span_seconds = 0;
+    report->est_offset = 0;
+    report->est_offset_err = 0;
+  }
+
+  report->resid_freq_ppm = 1.0e6 * inst->estimated_frequency;
+  report->skew_ppm = 1.0e6 * inst->skew;
+  report->sd = inst->std_dev;
+}
+
+/* ================================================== */
+
+double
+SST_GetJitterAsymmetry(SST_Stats inst)
+{
+  return inst->asymmetry;
+}
+
+/* ================================================== */
diff --git a/chrony_3_3/sourcestats.h b/chrony_3_3/sourcestats.h
new file mode 100644
index 0000000..f0a5ca9
--- /dev/null
+++ b/chrony_3_3/sourcestats.h
@@ -0,0 +1,147 @@
+/*
+  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 module that deals with the measurements and statistics of
+  each of the sources. */
+
+#ifndef GOT_SOURCESTATS_H
+#define GOT_SOURCESTATS_H
+
+#include "sysincl.h"
+
+#include "reports.h"
+
+typedef struct SST_Stats_Record *SST_Stats;
+
+/* Init and fini functions */
+extern void SST_Initialise(void);
+extern void SST_Finalise(void);
+
+/* This function creates a new instance of the statistics handler */
+extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr,
+                                    int min_samples, int max_samples,
+                                    double min_delay, double asymmetry);
+
+/* This function deletes an instance of the statistics handler. */
+extern void SST_DeleteInstance(SST_Stats inst);
+
+/* This function resets an instance */
+extern void SST_ResetInstance(SST_Stats inst);
+
+/* This function changes the reference ID and IP address */
+extern void SST_SetRefid(SST_Stats inst, uint32_t refid, IPAddr *addr);
+
+/* This function accumulates a single sample into the statistics handler
+
+   sample_time is the epoch at which the sample is to be considered to
+   have been made.
+
+   offset is the offset of the local clock relative to the source in
+   seconds.  Positive indicates that the local clock if FAST (contrary
+   to the NTP parts of the software)
+
+   stratum is the stratum of the source from which the sample came.
+  */
+
+extern void SST_AccumulateSample(SST_Stats inst, struct timespec *sample_time, double offset, double peer_delay, double peer_dispersion, double root_delay, double root_dispersion, int stratum);
+
+/* This function runs the linear regression operation on the data.  It
+   finds the set of most recent samples that give the tightest
+   confidence interval for the frequency, and truncates the register
+   down to that number of samples. */
+extern void SST_DoNewRegression(SST_Stats inst);
+
+/* Return the assumed worst case range of values that this source's
+   frequency lies within.  Frequency is defined as the amount of time
+   the local clock gains relative to the source per unit local clock
+   time. */
+extern void SST_GetFrequencyRange(SST_Stats inst, double *lo, double *hi);
+
+/* Get data needed for selection */
+extern void
+SST_GetSelectionData(SST_Stats inst, struct timespec *now,
+                     int *stratum,
+                     double *offset_lo_limit,
+                     double *offset_hi_limit,
+                     double *root_distance,
+                     double *variance,
+                     double *first_sample_ago,
+                     double *last_sample_ago,
+                     int *select_ok);
+
+/* Get data needed when setting up tracking on this source */
+extern void
+SST_GetTrackingData(SST_Stats inst, struct timespec *ref_time,
+                    double *average_offset, double *offset_sd,
+                    double *frequency, double *skew,
+                    double *root_delay, double *root_dispersion);
+
+/* This routine is called when the local machine clock parameters are
+   changed.  It adjusts all existing samples that we are holding for
+   each peer so that it looks like they were made under the new clock
+   regime rather than the old one.
+
+   when = cooked local time when the change occurs
+
+   dfreq = delta frequency. positive means the clock has been adjusted
+   because it was previously gaining time relative to the external
+   reference(s).
+
+   doffset = offset slewed onto local clock.  positive => local clock
+   has been made fast by that amount.
+
+*/
+
+extern void SST_SlewSamples(SST_Stats inst, struct timespec *when, double dfreq, double doffset);
+
+/* This routine is called when an indeterminate offset is introduced
+   into the local time. */
+extern void SST_AddDispersion(SST_Stats inst, double dispersion);
+
+/* Predict the offset of the local clock relative to a given source at
+   a given local cooked time. Positive indicates local clock is FAST
+   relative to reference. */
+extern double SST_PredictOffset(SST_Stats inst, struct timespec *when);
+
+/* Find the minimum round trip delay in the register */
+extern double SST_MinRoundTripDelay(SST_Stats inst);
+
+/* Get data needed for testing NTP delay */
+extern int SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
+                                double *last_sample_ago, double *predicted_offset,
+                                double *min_delay, double *skew, double *std_dev);
+
+extern void SST_SaveToFile(SST_Stats inst, FILE *out);
+
+extern int SST_LoadFromFile(SST_Stats inst, FILE *in);
+
+extern void SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timespec *now);
+
+extern void SST_DoSourcestatsReport(SST_Stats inst, RPT_SourcestatsReport *report, struct timespec *now);
+
+extern int SST_Samples(SST_Stats inst);
+
+extern double SST_GetJitterAsymmetry(SST_Stats inst);
+
+#endif /* GOT_SOURCESTATS_H */
+
diff --git a/chrony_3_3/srcparams.h b/chrony_3_3/srcparams.h
new file mode 100644
index 0000000..7a73bad
--- /dev/null
+++ b/chrony_3_3/srcparams.h
@@ -0,0 +1,78 @@
+/*
+  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 defining parameters that can be set on a per source basis
+  */
+
+#ifndef GOT_SRCPARAMS_H
+#define GOT_SRCPARAMS_H
+
+#include "sources.h"
+
+typedef struct {
+  int minpoll;
+  int maxpoll;
+  int online;
+  int auto_offline;
+  int presend_minpoll;
+  int burst;
+  int iburst;
+  int min_stratum;
+  int poll_target;
+  int version;
+  int max_sources;
+  int min_samples;
+  int max_samples;
+  int interleaved;
+  int sel_options;
+  uint32_t authkey;
+  double max_delay;
+  double max_delay_ratio;
+  double max_delay_dev_ratio;
+  double min_delay;
+  double asymmetry;
+  double offset;
+} SourceParameters;
+
+#define SRC_DEFAULT_PORT 123
+#define SRC_DEFAULT_MINPOLL 6
+#define SRC_DEFAULT_MAXPOLL 10
+#define SRC_DEFAULT_PRESEND_MINPOLL 100
+#define SRC_DEFAULT_MAXDELAY 3.0
+#define SRC_DEFAULT_MAXDELAYRATIO 0.0
+#define SRC_DEFAULT_MAXDELAYDEVRATIO 10.0
+#define SRC_DEFAULT_MINSTRATUM 0
+#define SRC_DEFAULT_POLLTARGET 8
+#define SRC_DEFAULT_MAXSOURCES 4
+#define SRC_DEFAULT_MINSAMPLES (-1)
+#define SRC_DEFAULT_MAXSAMPLES (-1)
+#define SRC_DEFAULT_ASYMMETRY 1.0
+#define INACTIVE_AUTHKEY 0
+
+/* Flags for source selection */
+#define SRC_SELECT_NOSELECT 0x1
+#define SRC_SELECT_PREFER 0x2
+#define SRC_SELECT_TRUST 0x4
+#define SRC_SELECT_REQUIRE 0x8
+
+#endif /* GOT_SRCPARAMS_H */
diff --git a/chrony_3_3/stubs.c b/chrony_3_3/stubs.c
new file mode 100644
index 0000000..eac81c0
--- /dev/null
+++ b/chrony_3_3/stubs.c
@@ -0,0 +1,418 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Function replacements needed when optional features are disabled.
+
+  */
+
+#include "config.h"
+
+#include "clientlog.h"
+#include "cmdmon.h"
+#include "keys.h"
+#include "logging.h"
+#include "manual.h"
+#include "memory.h"
+#include "nameserv.h"
+#include "nameserv_async.h"
+#include "ntp_core.h"
+#include "ntp_io.h"
+#include "ntp_sources.h"
+#include "ntp_signd.h"
+#include "privops.h"
+#include "refclock.h"
+#include "sched.h"
+#include "util.h"
+
+#ifndef FEAT_ASYNCDNS
+
+/* This is a blocking implementation used when asynchronous resolving is not available */
+
+struct DNS_Async_Instance {
+  const char *name;
+  DNS_NameResolveHandler handler;
+  void *arg;
+  int pipe[2];
+};
+
+static void
+resolve_name(int fd, int event, void *anything)
+{
+  struct DNS_Async_Instance *inst;
+  IPAddr addrs[DNS_MAX_ADDRESSES];
+  DNS_Status status;
+  int i;
+
+  inst = (struct DNS_Async_Instance *)anything;
+
+  SCH_RemoveFileHandler(inst->pipe[0]);
+  close(inst->pipe[0]);
+  close(inst->pipe[1]);
+
+  status = PRV_Name2IPAddress(inst->name, addrs, DNS_MAX_ADDRESSES);
+
+  for (i = 0; status == DNS_Success && i < DNS_MAX_ADDRESSES &&
+       addrs[i].family != IPADDR_UNSPEC; i++)
+    ;
+
+  (inst->handler)(status, i, addrs, inst->arg);
+
+  Free(inst);
+}
+
+void
+DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
+{
+  struct DNS_Async_Instance *inst;
+
+  inst = MallocNew(struct DNS_Async_Instance);
+  inst->name = name;
+  inst->handler = handler;
+  inst->arg = anything;
+
+  if (pipe(inst->pipe))
+    LOG_FATAL("pipe() failed");
+
+  UTI_FdSetCloexec(inst->pipe[0]);
+  UTI_FdSetCloexec(inst->pipe[1]);
+
+  SCH_AddFileHandler(inst->pipe[0], SCH_FILE_INPUT, resolve_name, inst);
+
+  if (write(inst->pipe[1], "", 1) < 0)
+    ;
+}
+
+#endif /* !FEAT_ASYNCDNS */
+
+#ifndef FEAT_CMDMON
+
+void
+CAM_Initialise(int family)
+{
+}
+
+void
+CAM_Finalise(void)
+{
+}
+
+void
+CAM_OpenUnixSocket(void)
+{
+}
+
+int
+CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
+{
+  return 1;
+}
+
+void
+MNL_Initialise(void)
+{
+}
+
+void
+MNL_Finalise(void)
+{
+}
+
+#endif /* !FEAT_CMDMON */
+
+#ifndef FEAT_NTP
+
+void
+NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
+{
+}
+
+void
+NCR_Initialise(void)
+{
+}
+
+void
+NCR_Finalise(void)
+{
+}
+
+int
+NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
+{
+  return 1;
+}
+
+int
+NCR_CheckAccessRestriction(IPAddr *ip_addr)
+{
+  return 0;
+}
+
+void
+NIO_Initialise(int family)
+{
+}
+
+void
+NIO_Finalise(void)
+{
+}
+
+void
+NSR_Initialise(void)
+{
+}
+
+void
+NSR_Finalise(void)
+{
+}
+
+NSR_Status
+NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
+{
+  return NSR_TooManySources;
+}
+
+void
+NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params)
+{
+}
+
+NSR_Status
+NSR_RemoveSource(NTP_Remote_Address *remote_addr)
+{
+  return NSR_NoSuchSource;
+}
+
+void
+NSR_RemoveAllSources(void)
+{
+}
+
+void
+NSR_HandleBadSource(IPAddr *address)
+{
+}
+
+void
+NSR_RefreshAddresses(void)
+{
+}
+
+void
+NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler)
+{
+  if (handler)
+    (handler)();
+}
+
+void
+NSR_ResolveSources(void)
+{
+}
+
+void NSR_StartSources(void)
+{
+}
+
+void NSR_AutoStartSources(void)
+{
+}
+
+int
+NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples,
+                        IPAddr *mask, IPAddr *address)
+{
+  return 0;
+}
+
+uint32_t
+NSR_GetLocalRefid(IPAddr *address)
+{
+  return 0;
+}
+
+int
+NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
+{
+  return 0;
+}
+
+int
+NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address)
+{
+  return 0;
+}
+
+int
+NSR_ModifyMinpoll(IPAddr *address, int new_minpoll)
+{
+  return 0;
+}
+
+int
+NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll)
+{
+  return 0;
+}
+
+int
+NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay)
+{
+  return 0;
+}
+
+int
+NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio)
+{
+  return 0;
+}
+
+int
+NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio)
+{
+  return 0;
+}
+
+int
+NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum)
+{
+  return 0;
+}
+
+int
+NSR_ModifyPolltarget(IPAddr *address, int new_poll_target)
+{
+  return 0;
+}
+
+void
+NSR_ReportSource(RPT_SourceReport *report, struct timespec *now)
+{
+  memset(report, 0, sizeof (*report));
+}
+  
+int
+NSR_GetNTPReport(RPT_NTPReport *report)
+{
+  return 0;
+}
+
+void
+NSR_GetActivityReport(RPT_ActivityReport *report)
+{
+  memset(report, 0, sizeof (*report));
+}
+
+#ifndef FEAT_CMDMON
+
+void
+CLG_Initialise(void)
+{
+}
+
+void
+CLG_Finalise(void)
+{
+}
+
+void
+DNS_SetAddressFamily(int family)
+{
+}
+
+DNS_Status
+DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
+{
+  return DNS_Failure;
+}
+
+void
+KEY_Initialise(void)
+{
+}
+
+void
+KEY_Finalise(void)
+{
+}
+
+#endif /* !FEAT_CMDMON */
+#endif /* !FEAT_NTP */
+
+#ifndef FEAT_REFCLOCK
+void
+RCL_Initialise(void)
+{
+}
+
+void
+RCL_Finalise(void)
+{
+}
+
+int
+RCL_AddRefclock(RefclockParameters *params)
+{
+  return 0;
+}
+
+void
+RCL_StartRefclocks(void)
+{
+}
+
+void
+RCL_ReportSource(RPT_SourceReport *report, struct timespec *now)
+{
+  memset(report, 0, sizeof (*report));
+}
+
+#endif /* !FEAT_REFCLOCK */
+
+#ifndef FEAT_SIGND
+
+void
+NSD_Initialise(void)
+{
+}
+
+void
+NSD_Finalise(void)
+{
+}
+
+int
+NSD_GetAuthDelay(uint32_t key_id)
+{
+  return 0;
+}
+
+int
+NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length)
+{
+  return 0;
+}
+
+#endif /* !FEAT_SIGND */
diff --git a/chrony_3_3/sys.c b/chrony_3_3/sys.c
new file mode 100644
index 0000000..4d68b37
--- /dev/null
+++ b/chrony_3_3/sys.c
@@ -0,0 +1,147 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  This file contains all the conditionally compiled bits that pull
+  in the various operating-system specific modules
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "sys.h"
+#include "sys_null.h"
+#include "logging.h"
+
+#if defined(LINUX)
+#include "sys_linux.h"
+#elif defined(SOLARIS)
+#include "sys_solaris.h"
+#elif defined(NETBSD) || defined(FREEBSD)
+#include "sys_netbsd.h"
+#elif defined(MACOSX)
+#include "sys_macosx.h"
+#endif
+
+/* ================================================== */
+
+static int null_driver;
+
+/* ================================================== */
+
+void
+SYS_Initialise(int clock_control)
+{
+  null_driver = !clock_control;
+  if (null_driver) {
+    SYS_Null_Initialise();
+    return;
+  }
+#if defined(LINUX)
+  SYS_Linux_Initialise();
+#elif defined(SOLARIS)
+  SYS_Solaris_Initialise();
+#elif defined(NETBSD) || defined(FREEBSD)
+  SYS_NetBSD_Initialise();
+#elif defined(MACOSX)
+  SYS_MacOSX_Initialise();
+#else
+#error Unknown system
+#endif
+}
+
+/* ================================================== */
+
+void
+SYS_Finalise(void)
+{
+  if (null_driver) {
+    SYS_Null_Finalise();
+    return;
+  }
+#if defined(LINUX)
+  SYS_Linux_Finalise();
+#elif defined(SOLARIS)
+  SYS_Solaris_Finalise();
+#elif defined(NETBSD) || defined(FREEBSD)
+  SYS_NetBSD_Finalise();
+#elif defined(MACOSX)
+  SYS_MacOSX_Finalise();
+#else
+#error Unknown system
+#endif
+}
+
+/* ================================================== */
+
+void SYS_DropRoot(uid_t uid, gid_t gid)
+{
+#if defined(LINUX) && defined (FEAT_PRIVDROP)
+  SYS_Linux_DropRoot(uid, gid, !null_driver);
+#elif defined(SOLARIS) && defined(FEAT_PRIVDROP)
+  SYS_Solaris_DropRoot(uid, gid);
+#elif (defined(NETBSD) || defined(FREEBSD)) && defined(FEAT_PRIVDROP)
+  SYS_NetBSD_DropRoot(uid, gid);
+#elif defined(MACOSX) && defined(FEAT_PRIVDROP)
+  SYS_MacOSX_DropRoot(uid, gid);
+#else
+  LOG_FATAL("dropping root privileges not supported");
+#endif
+}
+
+/* ================================================== */
+
+void SYS_EnableSystemCallFilter(int level)
+{
+#if defined(LINUX) && defined(FEAT_SCFILTER)
+  SYS_Linux_EnableSystemCallFilter(level);
+#else
+  LOG_FATAL("system call filter not supported");
+#endif
+}
+
+/* ================================================== */
+
+void SYS_SetScheduler(int SchedPriority)
+{
+#if defined(LINUX) && defined(HAVE_SCHED_SETSCHEDULER)
+  SYS_Linux_SetScheduler(SchedPriority);
+#elif defined(MACOSX)
+  SYS_MacOSX_SetScheduler(SchedPriority);
+#else
+  LOG_FATAL("scheduler priority setting not supported");
+#endif
+}
+
+/* ================================================== */
+
+void SYS_LockMemory(void)
+{
+#if defined(LINUX) && defined(HAVE_MLOCKALL)
+  SYS_Linux_MemLockAll(1);
+#else
+  LOG_FATAL("memory locking not supported");
+#endif
+}
+
+/* ================================================== */
diff --git a/chrony_3_3/sys.h b/chrony_3_3/sys.h
new file mode 100644
index 0000000..cb726f2
--- /dev/null
+++ b/chrony_3_3/sys.h
@@ -0,0 +1,48 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  This is the header for the file that links in the operating system-
+  specific parts of the software
+
+*/
+
+#ifndef GOT_SYS_H
+#define GOT_SYS_H
+
+/* Called at the start of the run to do initialisation */
+extern void SYS_Initialise(int clock_control);
+
+/* Called at the end of the run to do final clean-up */
+extern void SYS_Finalise(void);
+
+/* Drop root privileges to the specified user and group */
+extern void SYS_DropRoot(uid_t uid, gid_t gid);
+
+/* Enable a system call filter to allow only system calls
+   which chronyd normally needs after initialization */
+extern void SYS_EnableSystemCallFilter(int level);
+
+extern void SYS_SetScheduler(int SchedPriority);
+extern void SYS_LockMemory(void);
+
+#endif /* GOT_SYS_H */
diff --git a/chrony_3_3/sys_generic.c b/chrony_3_3/sys_generic.c
new file mode 100644
index 0000000..9c785d2
--- /dev/null
+++ b/chrony_3_3/sys_generic.c
@@ -0,0 +1,422 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2014-2015
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Generic driver functions to complete system-specific drivers
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "sys_generic.h"
+
+#include "conf.h"
+#include "local.h"
+#include "localp.h"
+#include "logging.h"
+#include "privops.h"
+#include "sched.h"
+#include "util.h"
+
+/* ================================================== */
+
+/* System clock drivers */
+static lcl_ReadFrequencyDriver drv_read_freq;
+static lcl_SetFrequencyDriver drv_set_freq;
+static lcl_SetSyncStatusDriver drv_set_sync_status;
+static lcl_AccrueOffsetDriver drv_accrue_offset;
+static lcl_OffsetCorrectionDriver drv_get_offset_correction;
+
+/* Current frequency as requested by the local module (in ppm) */
+static double base_freq;
+
+/* Maximum frequency that can be set by drv_set_freq (in ppm) */
+static double max_freq;
+
+/* Maximum expected delay in the actual frequency change (e.g. kernel ticks)
+   in local time */
+static double max_freq_change_delay;
+
+/* Maximum allowed frequency offset relative to the base frequency */
+static double max_corr_freq;
+
+/* Amount of outstanding offset to process */
+static double offset_register;
+
+/* Minimum offset to correct */
+#define MIN_OFFSET_CORRECTION 1.0e-9
+
+/* Current frequency offset between base_freq and the real clock frequency
+   as set by drv_set_freq (not in ppm) */
+static double slew_freq;
+
+/* Time (raw) of last update of slewing frequency and offset */
+static struct timespec slew_start;
+
+/* Limits for the slew timeout */
+#define MIN_SLEW_TIMEOUT 1.0
+#define MAX_SLEW_TIMEOUT 1.0e4
+
+/* Scheduler timeout ID for ending of the currently running slew */
+static SCH_TimeoutID slew_timeout_id;
+
+/* Suggested offset correction rate (correction time * offset) */
+static double correction_rate;
+
+/* Maximum expected offset correction error caused by delayed change in the
+   real frequency of the clock */
+static double slew_error;
+
+/* Minimum offset that the system driver can slew faster than the maximum
+   frequency offset that it allows to be set directly */
+static double fastslew_min_offset;
+
+/* Maximum slew rate of the system driver */
+static double fastslew_max_rate;
+
+/* Flag indicating that the system driver is currently slewing */
+static int fastslew_active;
+
+/* ================================================== */
+
+static void handle_end_of_slew(void *anything);
+static void update_slew(void);
+
+/* ================================================== */
+/* Adjust slew_start on clock step */
+
+static void
+handle_step(struct timespec *raw, struct timespec *cooked, double dfreq,
+            double doffset, LCL_ChangeType change_type, void *anything)
+{
+  if (change_type == LCL_ChangeUnknownStep) {
+    /* Reset offset and slewing */
+    slew_start = *raw;
+    offset_register = 0.0;
+    update_slew();
+  } else if (change_type == LCL_ChangeStep) {
+    UTI_AddDoubleToTimespec(&slew_start, -doffset, &slew_start);
+  }
+}
+
+/* ================================================== */
+
+static void
+start_fastslew(void)
+{
+  if (!drv_accrue_offset)
+    return;
+
+  drv_accrue_offset(offset_register, 0.0);
+
+  DEBUG_LOG("fastslew offset=%e", offset_register);
+
+  offset_register = 0.0;
+  fastslew_active = 1;
+}
+
+/* ================================================== */
+
+static void
+stop_fastslew(struct timespec *now)
+{
+  double corr;
+
+  if (!drv_get_offset_correction || !fastslew_active)
+    return;
+
+  /* Cancel the remaining offset */
+  drv_get_offset_correction(now, &corr, NULL);
+  drv_accrue_offset(corr, 0.0);
+  offset_register -= corr;
+}
+
+/* ================================================== */
+
+static double
+clamp_freq(double freq)
+{
+  if (freq > max_freq)
+    return max_freq;
+  if (freq < -max_freq)
+    return -max_freq;
+  return freq;
+}
+
+/* ================================================== */
+/* End currently running slew and start a new one */
+
+static void
+update_slew(void)
+{
+  struct timespec now, end_of_slew;
+  double old_slew_freq, total_freq, corr_freq, duration;
+
+  /* Remove currently running timeout */
+  SCH_RemoveTimeout(slew_timeout_id);
+
+  LCL_ReadRawTime(&now);
+
+  /* Adjust the offset register by achieved slew */
+  duration = UTI_DiffTimespecsToDouble(&now, &slew_start);
+  offset_register -= slew_freq * duration;
+
+  stop_fastslew(&now);
+
+  /* Estimate how long should the next slew take */
+  if (fabs(offset_register) < MIN_OFFSET_CORRECTION) {
+    duration = MAX_SLEW_TIMEOUT;
+  } else {
+    duration = correction_rate / fabs(offset_register);
+    if (duration < MIN_SLEW_TIMEOUT)
+      duration = MIN_SLEW_TIMEOUT;
+  }
+
+  /* Get frequency offset needed to slew the offset in the duration
+     and clamp it to the allowed maximum */
+  corr_freq = offset_register / duration;
+  if (corr_freq < -max_corr_freq)
+    corr_freq = -max_corr_freq;
+  else if (corr_freq > max_corr_freq)
+    corr_freq = max_corr_freq;
+
+  /* Let the system driver perform the slew if the requested frequency
+     offset is too large for the frequency driver */
+  if (drv_accrue_offset && fabs(corr_freq) >= fastslew_max_rate &&
+      fabs(offset_register) > fastslew_min_offset) {
+    start_fastslew();
+    corr_freq = 0.0;
+  }
+
+  /* Get the new real frequency and clamp it */
+  total_freq = clamp_freq(base_freq + corr_freq * (1.0e6 - base_freq));
+
+  /* Set the new frequency (the actual frequency returned by the call may be
+     slightly different from the requested frequency due to rounding) */
+  total_freq = (*drv_set_freq)(total_freq);
+
+  /* Compute the new slewing frequency, it's relative to the real frequency to
+     make the calculation in offset_convert() cheaper */
+  old_slew_freq = slew_freq;
+  slew_freq = (total_freq - base_freq) / (1.0e6 - total_freq);
+
+  /* Compute the dispersion introduced by changing frequency and add it
+     to all statistics held at higher levels in the system */
+  slew_error = fabs((old_slew_freq - slew_freq) * max_freq_change_delay);
+  if (slew_error >= MIN_OFFSET_CORRECTION)
+    lcl_InvokeDispersionNotifyHandlers(slew_error);
+
+  /* Compute the duration of the slew and clamp it.  If the slewing frequency
+     is zero or has wrong sign (e.g. due to rounding in the frequency driver or
+     when base_freq is larger than max_freq, or fast slew is active), use the
+     maximum timeout and try again on the next update. */
+  if (fabs(offset_register) < MIN_OFFSET_CORRECTION ||
+      offset_register * slew_freq <= 0.0) {
+    duration = MAX_SLEW_TIMEOUT;
+  } else {
+    duration = offset_register / slew_freq;
+    if (duration < MIN_SLEW_TIMEOUT)
+      duration = MIN_SLEW_TIMEOUT;
+    else if (duration > MAX_SLEW_TIMEOUT)
+      duration = MAX_SLEW_TIMEOUT;
+  }
+
+  /* Restart timer for the next update */
+  UTI_AddDoubleToTimespec(&now, duration, &end_of_slew);
+  slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
+  slew_start = now;
+
+  DEBUG_LOG("slew offset=%e corr_rate=%e base_freq=%f total_freq=%f slew_freq=%e duration=%f slew_error=%e",
+      offset_register, correction_rate, base_freq, total_freq, slew_freq,
+      duration, slew_error);
+}
+
+/* ================================================== */
+
+static void
+handle_end_of_slew(void *anything)
+{
+  slew_timeout_id = 0;
+  update_slew();
+}
+
+/* ================================================== */
+
+static double
+read_frequency(void)
+{
+  return base_freq;
+}
+
+/* ================================================== */
+
+static double
+set_frequency(double freq_ppm)
+{
+  base_freq = freq_ppm;
+  update_slew();
+
+  return base_freq;
+}
+
+/* ================================================== */
+
+static void
+accrue_offset(double offset, double corr_rate)
+{
+  offset_register += offset;
+  correction_rate = corr_rate;
+
+  update_slew();
+}
+
+/* ================================================== */
+/* Determine the correction to generate the cooked time for given raw time */
+
+static void
+offset_convert(struct timespec *raw,
+               double *corr, double *err)
+{
+  double duration, fastslew_corr, fastslew_err;
+
+  duration = UTI_DiffTimespecsToDouble(raw, &slew_start);
+
+  if (drv_get_offset_correction && fastslew_active) {
+    drv_get_offset_correction(raw, &fastslew_corr, &fastslew_err);
+    if (fastslew_corr == 0.0 && fastslew_err == 0.0)
+      fastslew_active = 0;
+  } else {
+    fastslew_corr = fastslew_err = 0.0;
+  }
+
+  *corr = slew_freq * duration + fastslew_corr - offset_register;
+
+  if (err) {
+    *err = fastslew_err;
+    if (fabs(duration) <= max_freq_change_delay)
+      *err += slew_error;
+  }
+}
+
+/* ================================================== */
+/* Positive means currently fast of true time, i.e. jump backwards */
+
+static int
+apply_step_offset(double offset)
+{
+  struct timespec old_time, new_time;
+  struct timeval new_time_tv;
+  double err;
+
+  LCL_ReadRawTime(&old_time);
+  UTI_AddDoubleToTimespec(&old_time, -offset, &new_time);
+  UTI_TimespecToTimeval(&new_time, &new_time_tv);
+
+  if (PRV_SetTime(&new_time_tv, NULL) < 0) {
+    DEBUG_LOG("settimeofday() failed");
+    return 0;
+  }
+
+  LCL_ReadRawTime(&old_time);
+  err = UTI_DiffTimespecsToDouble(&old_time, &new_time);
+
+  lcl_InvokeDispersionNotifyHandlers(fabs(err));
+
+  return 1;
+}
+
+/* ================================================== */
+
+static void
+set_sync_status(int synchronised, double est_error, double max_error)
+{
+  double offset;
+
+  offset = fabs(offset_register);
+  if (est_error < offset)
+    est_error = offset;
+  max_error += offset;
+
+  if (drv_set_sync_status)
+    drv_set_sync_status(synchronised, est_error, max_error);
+}
+
+/* ================================================== */
+
+void
+SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_delay,
+                               lcl_ReadFrequencyDriver sys_read_freq,
+                               lcl_SetFrequencyDriver sys_set_freq,
+                               lcl_ApplyStepOffsetDriver sys_apply_step_offset,
+                               double min_fastslew_offset, double max_fastslew_rate,
+                               lcl_AccrueOffsetDriver sys_accrue_offset,
+                               lcl_OffsetCorrectionDriver sys_get_offset_correction,
+                               lcl_SetLeapDriver sys_set_leap,
+                               lcl_SetSyncStatusDriver sys_set_sync_status)
+{
+  max_freq = max_set_freq_ppm;
+  max_freq_change_delay = max_set_freq_delay * (1.0 + max_freq / 1.0e6);
+  drv_read_freq = sys_read_freq;
+  drv_set_freq = sys_set_freq;
+  drv_accrue_offset = sys_accrue_offset;
+  drv_get_offset_correction = sys_get_offset_correction;
+  drv_set_sync_status = sys_set_sync_status;
+
+  base_freq = (*drv_read_freq)();
+  slew_freq = 0.0;
+  offset_register = 0.0;
+
+  max_corr_freq = CNF_GetMaxSlewRate() / 1.0e6;
+
+  fastslew_min_offset = min_fastslew_offset;
+  fastslew_max_rate = max_fastslew_rate / 1.0e6;
+  fastslew_active = 0;
+
+  lcl_RegisterSystemDrivers(read_frequency, set_frequency,
+                            accrue_offset, sys_apply_step_offset ?
+                              sys_apply_step_offset : apply_step_offset,
+                            offset_convert, sys_set_leap, set_sync_status);
+
+  LCL_AddParameterChangeHandler(handle_step, NULL);
+}
+
+/* ================================================== */
+
+void
+SYS_Generic_Finalise(void)
+{
+  struct timespec now;
+
+  /* Must *NOT* leave a slew running - clock could drift way off
+     if the daemon is not restarted */
+
+  SCH_RemoveTimeout(slew_timeout_id);
+  slew_timeout_id = 0;
+
+  (*drv_set_freq)(clamp_freq(base_freq));
+
+  LCL_ReadRawTime(&now);
+  stop_fastslew(&now);
+}
+
+/* ================================================== */
diff --git a/chrony_3_3/sys_generic.h b/chrony_3_3/sys_generic.h
new file mode 100644
index 0000000..d9b252e
--- /dev/null
+++ b/chrony_3_3/sys_generic.h
@@ -0,0 +1,46 @@
+/*
+  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 generic driver
+  */
+
+#ifndef GOT_SYS_GENERIC_H
+#define GOT_SYS_GENERIC_H
+
+#include "localp.h"
+
+/* Register a completed driver that implements offset functions on top of
+   provided frequency functions */
+extern void SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_delay,
+                                           lcl_ReadFrequencyDriver sys_read_freq,
+                                           lcl_SetFrequencyDriver sys_set_freq,
+                                           lcl_ApplyStepOffsetDriver sys_apply_step_offset,
+                                           double min_fastslew_offset, double max_fastslew_rate,
+                                           lcl_AccrueOffsetDriver sys_accrue_offset,
+                                           lcl_OffsetCorrectionDriver sys_get_offset_correction,
+                                           lcl_SetLeapDriver sys_set_leap,
+                                           lcl_SetSyncStatusDriver sys_set_sync_status);
+
+extern void SYS_Generic_Finalise(void);
+
+#endif  /* GOT_SYS_GENERIC_H */
diff --git a/chrony_3_3/sys_linux.c b/chrony_3_3/sys_linux.c
new file mode 100644
index 0000000..f4b532d
--- /dev/null
+++ b/chrony_3_3/sys_linux.c
@@ -0,0 +1,896 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) John G. Hasler  2009
+ * Copyright (C) Miroslav Lichvar  2009-2012, 2014-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 is the module specific to the Linux operating system.
+
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include <sys/utsname.h>
+
+#if defined(HAVE_SCHED_SETSCHEDULER)
+#  include <sched.h>
+#endif
+
+#if defined(HAVE_MLOCKALL)
+#  include <sys/mman.h>
+#include <sys/resource.h>
+#endif
+
+#ifdef FEAT_PRIVDROP
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#endif
+
+#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
+#include <linux/ptp_clock.h>
+#endif
+
+#ifdef FEAT_SCFILTER
+#include <sys/prctl.h>
+#include <seccomp.h>
+#include <termios.h>
+#ifdef FEAT_PPS
+#include <linux/pps.h>
+#endif
+#ifdef FEAT_RTC
+#include <linux/rtc.h>
+#endif
+#ifdef HAVE_LINUX_TIMESTAMPING
+#include <linux/sockios.h>
+#endif
+#endif
+
+#include "sys_linux.h"
+#include "sys_timex.h"
+#include "conf.h"
+#include "local.h"
+#include "logging.h"
+#include "privops.h"
+#include "util.h"
+
+/* Frequency scale to convert from ppm to the timex freq */
+#define FREQ_SCALE (double)(1 << 16)
+
+/* Definitions used if missed in the system headers */
+#ifndef ADJ_SETOFFSET
+#define ADJ_SETOFFSET           0x0100  /* add 'time' to current time */
+#endif
+#ifndef ADJ_NANO
+#define ADJ_NANO                0x2000  /* select nanosecond resolution */
+#endif
+
+/* This is the uncompensated system tick value */
+static int nominal_tick;
+
+/* Current tick value */
+static int current_delta_tick;
+
+/* The maximum amount by which 'tick' can be biased away from 'nominal_tick'
+   (sys_adjtimex() in the kernel bounds this to 10%) */
+static int max_tick_bias;
+
+/* The kernel USER_HZ constant */
+static int hz;
+static double dhz; /* And dbl prec version of same for arithmetic */
+
+/* Flag indicating whether adjtimex() can step the clock */
+static int have_setoffset;
+
+/* The assumed rate at which the effective frequency and tick values are
+   updated in the kernel */
+static int tick_update_hz;
+
+/* ================================================== */
+
+inline static long
+our_round(double x)
+{
+  long y;
+
+  if (x > 0.0)
+    y = x + 0.5;
+  else
+    y = x - 0.5;
+
+  return y;
+}
+
+/* ================================================== */
+/* Positive means currently fast of true time, i.e. jump backwards */
+
+static int
+apply_step_offset(double offset)
+{
+  struct timex txc;
+
+  txc.modes = ADJ_SETOFFSET | ADJ_NANO;
+  txc.time.tv_sec = -offset;
+  txc.time.tv_usec = 1.0e9 * (-offset - txc.time.tv_sec);
+  if (txc.time.tv_usec < 0) {
+    txc.time.tv_sec--;
+    txc.time.tv_usec += 1000000000;
+  }
+
+  if (SYS_Timex_Adjust(&txc, 1) < 0)
+    return 0;
+
+  return 1;
+}
+
+/* ================================================== */
+/* This call sets the Linux kernel frequency to a given value in parts
+   per million relative to the nominal running frequency.  Nominal is taken to
+   be tick=10000, freq=0 (for a USER_HZ==100 system, other values otherwise).
+   The convention is that this is called with a positive argument if the local
+   clock runs fast when uncompensated.  */
+
+static double
+set_frequency(double freq_ppm)
+{
+  struct timex txc;
+  long required_tick;
+  double required_freq;
+  int required_delta_tick;
+
+  required_delta_tick = our_round(freq_ppm / dhz);
+
+  /* Older kernels (pre-2.6.18) don't apply the frequency offset exactly as
+     set by adjtimex() and a scaling constant (that depends on the internal
+     kernel HZ constant) would be needed to compensate for the error. Because
+     chronyd is closed loop it doesn't matter much if we don't scale the
+     required frequency, but we want to prevent thrashing between two states
+     when the system's frequency error is close to a multiple of USER_HZ.  With
+     USER_HZ <= 250, the maximum frequency adjustment of 500 ppm overlaps at
+     least two ticks and we can stick to the current tick if it's next to the
+     required tick. */
+  if (hz <= 250 && (required_delta_tick + 1 == current_delta_tick ||
+                    required_delta_tick - 1 == current_delta_tick)) {
+    required_delta_tick = current_delta_tick;
+  }
+
+  required_freq = -(freq_ppm - dhz * required_delta_tick);
+  required_tick = nominal_tick - required_delta_tick;
+
+  txc.modes = ADJ_TICK | ADJ_FREQUENCY;
+  txc.freq = required_freq * FREQ_SCALE;
+  txc.tick = required_tick;
+
+  SYS_Timex_Adjust(&txc, 0);
+
+  current_delta_tick = required_delta_tick;
+
+  return dhz * current_delta_tick - txc.freq / FREQ_SCALE;
+}
+
+/* ================================================== */
+/* Read the ppm frequency from the kernel */
+
+static double
+read_frequency(void)
+{
+  struct timex txc;
+
+  txc.modes = 0;
+
+  SYS_Timex_Adjust(&txc, 0);
+
+  current_delta_tick = nominal_tick - txc.tick;
+
+  return dhz * current_delta_tick - txc.freq / FREQ_SCALE;
+}
+
+/* ================================================== */
+
+/* Estimate the value of USER_HZ given the value of txc.tick that chronyd finds when
+ * it starts.  The only credible values are 100 (Linux/x86) or powers of 2.
+ * Also, the bounds checking inside the kernel's adjtimex system call enforces
+ * a +/- 10% movement of tick away from the nominal value 1e6/USER_HZ. */
+
+static int
+guess_hz(void)
+{
+  struct timex txc;
+  int i, tick, tick_lo, tick_hi, ihz;
+  double tick_nominal;
+
+  txc.modes = 0;
+  SYS_Timex_Adjust(&txc, 0);
+  tick = txc.tick;
+
+  /* Pick off the hz=100 case first */
+  if (tick >= 9000 && tick <= 11000) {
+    return 100;
+  }
+
+  for (i=4; i<16; i++) { /* surely 16 .. 32768 is a wide enough range? */
+    ihz = 1 << i;
+    tick_nominal = 1.0e6 / (double) ihz;
+    tick_lo = (int)(0.5 + tick_nominal*2.0/3.0);
+    tick_hi = (int)(0.5 + tick_nominal*4.0/3.0);
+    
+    if (tick_lo < tick && tick <= tick_hi) {
+      return ihz;
+    }
+  }
+
+  /* oh dear.  doomed. */
+  LOG_FATAL("Can't determine hz from tick %d", tick);
+
+  return 0;
+}
+
+/* ================================================== */
+
+static int
+get_hz(void)
+{
+#ifdef _SC_CLK_TCK
+  int hz;
+
+  if ((hz = sysconf(_SC_CLK_TCK)) < 1)
+    return 0;
+
+  return hz;
+#else
+  return 0;
+#endif
+}
+
+/* ================================================== */
+
+static int
+kernelvercmp(int major1, int minor1, int patch1,
+    int major2, int minor2, int patch2)
+{
+  if (major1 != major2)
+    return major1 - major2;
+  if (minor1 != minor2)
+    return minor1 - minor2;
+  return patch1 - patch2;
+}
+
+/* ================================================== */
+
+static void
+get_kernel_version(int *major, int *minor, int *patch)
+{
+  struct utsname uts;
+
+  if (uname(&uts) < 0)
+    LOG_FATAL("uname() failed");
+
+  *patch = 0;
+  if (sscanf(uts.release, "%d.%d.%d", major, minor, patch) < 2)
+    LOG_FATAL("Could not parse kernel version");
+}
+
+/* ================================================== */
+
+/* Compute the scaling to use on any frequency we set, according to
+   the vintage of the Linux kernel being used. */
+
+static void
+get_version_specific_details(void)
+{
+  int major, minor, patch;
+  
+  hz = get_hz();
+
+  if (!hz)
+    hz = guess_hz();
+
+  dhz = (double) hz;
+  nominal_tick = (1000000L + (hz/2))/hz; /* Mirror declaration in kernel */
+  max_tick_bias = nominal_tick / 10;
+
+  /* We can't reliably detect the internal kernel HZ, it may not even be fixed
+     (CONFIG_NO_HZ aka tickless), assume the lowest commonly used fixed rate */
+  tick_update_hz = 100;
+
+  get_kernel_version(&major, &minor, &patch);
+  DEBUG_LOG("Linux kernel major=%d minor=%d patch=%d", major, minor, patch);
+
+  if (kernelvercmp(major, minor, patch, 2, 2, 0) < 0) {
+    LOG_FATAL("Kernel version not supported, sorry.");
+  }
+
+  if (kernelvercmp(major, minor, patch, 2, 6, 27) >= 0 &&
+      kernelvercmp(major, minor, patch, 2, 6, 33) < 0) {
+    /* Tickless kernels before 2.6.33 accumulated ticks only in
+       half-second intervals */
+    tick_update_hz = 2;
+  }
+
+  /* ADJ_SETOFFSET support */
+  if (kernelvercmp(major, minor, patch, 2, 6, 39) < 0) {
+    have_setoffset = 0;
+  } else {
+    have_setoffset = 1;
+  }
+
+  DEBUG_LOG("hz=%d nominal_tick=%d max_tick_bias=%d",
+      hz, nominal_tick, max_tick_bias);
+}
+
+/* ================================================== */
+
+static void
+reset_adjtime_offset(void)
+{
+  struct timex txc;
+
+  /* Reset adjtime() offset */
+  txc.modes = ADJ_OFFSET_SINGLESHOT;
+  txc.offset = 0;
+
+  SYS_Timex_Adjust(&txc, 0);
+}
+
+/* ================================================== */
+
+static int
+test_step_offset(void)
+{
+  struct timex txc;
+
+  /* Zero maxerror and check it's reset to a maximum after ADJ_SETOFFSET.
+     This seems to be the only way how to verify that the kernel really
+     supports the ADJ_SETOFFSET mode as it doesn't return an error on unknown
+     mode. */
+
+  txc.modes = MOD_MAXERROR;
+  txc.maxerror = 0;
+
+  if (SYS_Timex_Adjust(&txc, 1) < 0 || txc.maxerror != 0)
+    return 0;
+
+  txc.modes = ADJ_SETOFFSET | ADJ_NANO;
+  txc.time.tv_sec = 0;
+  txc.time.tv_usec = 0;
+
+  if (SYS_Timex_Adjust(&txc, 1) < 0 || txc.maxerror < 100000)
+    return 0;
+
+  return 1;
+}
+
+/* ================================================== */
+
+static void
+report_time_adjust_blockers(void)
+{
+#ifdef FEAT_PRIVDROP
+  if (CAP_IS_SUPPORTED(CAP_SYS_TIME) && cap_get_bound(CAP_SYS_TIME))
+    return;
+  LOG(LOGS_WARN, "CAP_SYS_TIME not present");
+#endif
+}
+
+/* ================================================== */
+/* Initialisation code for this module */
+
+void
+SYS_Linux_Initialise(void)
+{
+  get_version_specific_details();
+
+  report_time_adjust_blockers();
+
+  reset_adjtime_offset();
+
+  if (have_setoffset && !test_step_offset()) {
+    LOG(LOGS_INFO, "adjtimex() doesn't support ADJ_SETOFFSET");
+    have_setoffset = 0;
+  }
+
+  SYS_Timex_InitialiseWithFunctions(1.0e6 * max_tick_bias / nominal_tick,
+                                    1.0 / tick_update_hz,
+                                    read_frequency, set_frequency,
+                                    have_setoffset ? apply_step_offset : NULL,
+                                    0.0, 0.0, NULL, NULL);
+}
+
+/* ================================================== */
+/* Finalisation code for this module */
+
+void
+SYS_Linux_Finalise(void)
+{
+  SYS_Timex_Finalise();
+}
+
+/* ================================================== */
+
+#ifdef FEAT_PRIVDROP
+void
+SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control)
+{
+  char cap_text[256];
+  cap_t cap;
+
+  if (prctl(PR_SET_KEEPCAPS, 1)) {
+    LOG_FATAL("prctl() failed");
+  }
+  
+  UTI_DropRoot(uid, gid);
+
+  /* Keep CAP_NET_BIND_SERVICE only if a server NTP port can be opened
+     and keep CAP_SYS_TIME only if the clock control is enabled */
+  if (snprintf(cap_text, sizeof (cap_text), "%s %s",
+               CNF_GetNTPPort() ? "cap_net_bind_service=ep" : "",
+               clock_control ? "cap_sys_time=ep" : "") >= sizeof (cap_text))
+    assert(0);
+
+  if ((cap = cap_from_text(cap_text)) == NULL) {
+    LOG_FATAL("cap_from_text() failed");
+  }
+
+  if (cap_set_proc(cap)) {
+    LOG_FATAL("cap_set_proc() failed");
+  }
+
+  cap_free(cap);
+}
+#endif
+
+/* ================================================== */
+
+#ifdef FEAT_SCFILTER
+static
+void check_seccomp_applicability(void)
+{
+  int mail_enabled;
+  double mail_threshold;
+  char *mail_user;
+
+  CNF_GetMailOnChange(&mail_enabled, &mail_threshold, &mail_user);
+  if (mail_enabled)
+    LOG_FATAL("mailonchange directive cannot be used with -F enabled");
+}
+
+/* ================================================== */
+
+void
+SYS_Linux_EnableSystemCallFilter(int level)
+{
+  const int syscalls[] = {
+    /* Clock */
+    SCMP_SYS(adjtimex), SCMP_SYS(clock_gettime), SCMP_SYS(gettimeofday),
+    SCMP_SYS(settimeofday), SCMP_SYS(time),
+    /* Process */
+    SCMP_SYS(clone), SCMP_SYS(exit), SCMP_SYS(exit_group), SCMP_SYS(getpid),
+    SCMP_SYS(getrlimit), SCMP_SYS(rt_sigaction), SCMP_SYS(rt_sigreturn),
+    SCMP_SYS(rt_sigprocmask), SCMP_SYS(set_tid_address), SCMP_SYS(sigreturn),
+    SCMP_SYS(wait4),
+    /* Memory */
+    SCMP_SYS(brk), SCMP_SYS(madvise), SCMP_SYS(mmap), SCMP_SYS(mmap2),
+    SCMP_SYS(mprotect), SCMP_SYS(mremap), SCMP_SYS(munmap), SCMP_SYS(shmdt),
+    /* Filesystem */
+    SCMP_SYS(access), SCMP_SYS(chmod), SCMP_SYS(chown), SCMP_SYS(chown32),
+    SCMP_SYS(fstat), SCMP_SYS(fstat64), SCMP_SYS(getdents), SCMP_SYS(getdents64),
+    SCMP_SYS(lseek), SCMP_SYS(rename), SCMP_SYS(stat), SCMP_SYS(stat64),
+    SCMP_SYS(statfs), SCMP_SYS(statfs64), SCMP_SYS(unlink),
+    /* Socket */
+    SCMP_SYS(bind), SCMP_SYS(connect), SCMP_SYS(getsockname), SCMP_SYS(getsockopt),
+    SCMP_SYS(recvfrom), SCMP_SYS(recvmmsg), SCMP_SYS(recvmsg),
+    SCMP_SYS(sendmmsg), SCMP_SYS(sendmsg), SCMP_SYS(sendto),
+    /* TODO: check socketcall arguments */
+    SCMP_SYS(socketcall),
+    /* General I/O */
+    SCMP_SYS(_newselect), SCMP_SYS(close), SCMP_SYS(open), SCMP_SYS(openat), SCMP_SYS(pipe),
+    SCMP_SYS(poll), SCMP_SYS(read), SCMP_SYS(futex), SCMP_SYS(select),
+    SCMP_SYS(set_robust_list), SCMP_SYS(write),
+    /* Miscellaneous */
+    SCMP_SYS(getrandom), SCMP_SYS(sysinfo), SCMP_SYS(uname),
+  };
+
+  const int socket_domains[] = {
+    AF_NETLINK, AF_UNIX, AF_INET,
+#ifdef FEAT_IPV6
+    AF_INET6,
+#endif
+  };
+
+  const static int socket_options[][2] = {
+    { SOL_IP, IP_PKTINFO }, { SOL_IP, IP_FREEBIND },
+#ifdef FEAT_IPV6
+    { SOL_IPV6, IPV6_V6ONLY }, { SOL_IPV6, IPV6_RECVPKTINFO },
+#endif
+    { SOL_SOCKET, SO_BROADCAST }, { SOL_SOCKET, SO_REUSEADDR },
+    { SOL_SOCKET, SO_TIMESTAMP }, { SOL_SOCKET, SO_TIMESTAMPNS },
+#ifdef HAVE_LINUX_TIMESTAMPING
+    { SOL_SOCKET, SO_SELECT_ERR_QUEUE }, { SOL_SOCKET, SO_TIMESTAMPING },
+#endif
+  };
+
+  const static int fcntls[] = { F_GETFD, F_SETFD };
+
+  const static unsigned long ioctls[] = {
+    FIONREAD, TCGETS,
+#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
+    PTP_EXTTS_REQUEST, PTP_SYS_OFFSET,
+#ifdef PTP_PIN_SETFUNC
+    PTP_PIN_SETFUNC,
+#endif
+#ifdef PTP_SYS_OFFSET_PRECISE
+    PTP_SYS_OFFSET_PRECISE,
+#endif
+#endif
+#ifdef FEAT_PPS
+    PPS_FETCH,
+#endif
+#ifdef FEAT_RTC
+    RTC_RD_TIME, RTC_SET_TIME, RTC_UIE_ON, RTC_UIE_OFF,
+#endif
+#ifdef HAVE_LINUX_TIMESTAMPING
+    SIOCETHTOOL,
+#endif
+  };
+
+  scmp_filter_ctx *ctx;
+  int i;
+
+  /* Check if the chronyd configuration is supported */
+  check_seccomp_applicability();
+
+  /* Start the helper process, which will run without any seccomp filter.  It
+     will be used for getaddrinfo(), for which it's difficult to maintain a
+     list of required system calls (with glibc it depends on what NSS modules
+     are installed and enabled on the system). */
+  PRV_StartHelper();
+
+  ctx = seccomp_init(level > 0 ? SCMP_ACT_KILL : SCMP_ACT_TRAP);
+  if (ctx == NULL)
+      LOG_FATAL("Failed to initialize seccomp");
+
+  /* Add system calls that are always allowed */
+  for (i = 0; i < (sizeof (syscalls) / sizeof (*syscalls)); i++) {
+    if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls[i], 0) < 0)
+      goto add_failed;
+  }
+
+  /* Allow sockets to be created only in selected domains */
+  for (i = 0; i < sizeof (socket_domains) / sizeof (*socket_domains); i++) {
+    if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
+                         SCMP_A0(SCMP_CMP_EQ, socket_domains[i])) < 0)
+      goto add_failed;
+  }
+
+  /* Allow setting only selected sockets options */
+  for (i = 0; i < sizeof (socket_options) / sizeof (*socket_options); i++) {
+    if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), 3,
+                         SCMP_A1(SCMP_CMP_EQ, socket_options[i][0]),
+                         SCMP_A2(SCMP_CMP_EQ, socket_options[i][1]),
+                         SCMP_A4(SCMP_CMP_LE, sizeof (int))) < 0)
+      goto add_failed;
+  }
+
+  /* Allow only selected fcntl calls */
+  for (i = 0; i < sizeof (fcntls) / sizeof (*fcntls); i++) {
+    if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1,
+                         SCMP_A1(SCMP_CMP_EQ, fcntls[i])) < 0 ||
+        seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64), 1,
+                         SCMP_A1(SCMP_CMP_EQ, fcntls[i])) < 0)
+      goto add_failed;
+  }
+
+  /* Allow only selected ioctls */
+  for (i = 0; i < sizeof (ioctls) / sizeof (*ioctls); i++) {
+    if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
+                         SCMP_A1(SCMP_CMP_EQ, ioctls[i])) < 0)
+      goto add_failed;
+  }
+
+  if (seccomp_load(ctx) < 0)
+    LOG_FATAL("Failed to load seccomp rules");
+
+  LOG(LOGS_INFO, "Loaded seccomp filter");
+  seccomp_release(ctx);
+  return;
+
+add_failed:
+  LOG_FATAL("Failed to add seccomp rules");
+}
+#endif
+
+/* ================================================== */
+
+#if defined(HAVE_SCHED_SETSCHEDULER)
+  /* Install SCHED_FIFO real-time scheduler with specified priority */
+void SYS_Linux_SetScheduler(int SchedPriority)
+{
+  int pmax, pmin;
+  struct sched_param sched;
+
+  if (SchedPriority < 1 || SchedPriority > 99) {
+    LOG_FATAL("Bad scheduler priority: %d", SchedPriority);
+  } else {
+    sched.sched_priority = SchedPriority;
+    pmax = sched_get_priority_max(SCHED_FIFO);
+    pmin = sched_get_priority_min(SCHED_FIFO);
+    if ( SchedPriority > pmax ) {
+      sched.sched_priority = pmax;
+    }
+    else if ( SchedPriority < pmin ) {
+      sched.sched_priority = pmin;
+    }
+    if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 ) {
+      LOG(LOGS_ERR, "sched_setscheduler() failed");
+    }
+    else {
+      DEBUG_LOG("Enabled SCHED_FIFO with priority %d",
+          sched.sched_priority);
+    }
+  }
+}
+#endif /* HAVE_SCHED_SETSCHEDULER */
+
+#if defined(HAVE_MLOCKALL)
+/* Lock the process into RAM so that it will never be swapped out */ 
+void SYS_Linux_MemLockAll(int LockAll)
+{
+  struct rlimit rlim;
+  if (LockAll == 1 ) {
+    /* Make sure that we will be able to lock all the memory we need */
+    /* even after dropping privileges.  This does not actually reaerve any memory */
+    rlim.rlim_max = RLIM_INFINITY;
+    rlim.rlim_cur = RLIM_INFINITY;
+    if (setrlimit(RLIMIT_MEMLOCK, &rlim) < 0) {
+      LOG(LOGS_ERR, "setrlimit() failed: not locking into RAM");
+    }
+    else {
+      if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) {
+	LOG(LOGS_ERR, "mlockall() failed");
+      }
+      else {
+	DEBUG_LOG("Successfully locked into RAM");
+      }
+    }
+  }
+}
+#endif /* HAVE_MLOCKALL */
+
+/* ================================================== */
+
+int
+SYS_Linux_CheckKernelVersion(int req_major, int req_minor)
+{
+  int major, minor, patch;
+
+  get_kernel_version(&major, &minor, &patch);
+
+  return kernelvercmp(req_major, req_minor, 0, major, minor, patch) <= 0;
+}
+
+/* ================================================== */
+
+#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
+
+#define PHC_READINGS 10
+
+static int
+get_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
+               struct timespec *sys_ts, double *err)
+{
+  struct ptp_sys_offset sys_off;
+  struct timespec ts1, ts2, ts3, phc_tss[PHC_READINGS], sys_tss[PHC_READINGS];
+  double min_delay = 0.0, delays[PHC_READINGS], phc_sum, sys_sum, sys_prec;
+  int i, n;
+
+  /* Silence valgrind */
+  memset(&sys_off, 0, sizeof (sys_off));
+
+  sys_off.n_samples = PHC_READINGS;
+
+  if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
+    DEBUG_LOG("ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
+    return 0;
+  }
+
+  for (i = 0; i < PHC_READINGS; i++) {
+    ts1.tv_sec = sys_off.ts[i * 2].sec;
+    ts1.tv_nsec = sys_off.ts[i * 2].nsec;
+    ts2.tv_sec = sys_off.ts[i * 2 + 1].sec;
+    ts2.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
+    ts3.tv_sec = sys_off.ts[i * 2 + 2].sec;
+    ts3.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
+
+    sys_tss[i] = ts1;
+    phc_tss[i] = ts2;
+    delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1);
+
+    if (delays[i] < 0.0) {
+      /* Step in the middle of a PHC reading? */
+      DEBUG_LOG("Bad PTP_SYS_OFFSET sample delay=%e", delays[i]);
+      return 0;
+    }
+
+    if (!i || delays[i] < min_delay)
+      min_delay = delays[i];
+  }
+
+  sys_prec = LCL_GetSysPrecisionAsQuantum();
+
+  /* Combine best readings */
+  for (i = n = 0, phc_sum = sys_sum = 0.0; i < PHC_READINGS; i++) {
+    if (delays[i] > min_delay + MAX(sys_prec, precision))
+      continue;
+
+    phc_sum += UTI_DiffTimespecsToDouble(&phc_tss[i], &phc_tss[0]);
+    sys_sum += UTI_DiffTimespecsToDouble(&sys_tss[i], &sys_tss[0]) + delays[i] / 2.0;
+    n++;
+  }
+
+  assert(n);
+
+  UTI_AddDoubleToTimespec(&phc_tss[0], phc_sum / n, phc_ts);
+  UTI_AddDoubleToTimespec(&sys_tss[0], sys_sum / n, sys_ts);
+  *err = MAX(min_delay / 2.0, precision);
+
+  return 1;
+}
+/* ================================================== */
+
+static int
+get_precise_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
+		       struct timespec *sys_ts, double *err)
+{
+#ifdef PTP_SYS_OFFSET_PRECISE
+  struct ptp_sys_offset_precise sys_off;
+
+  /* Silence valgrind */
+  memset(&sys_off, 0, sizeof (sys_off));
+
+  if (ioctl(phc_fd, PTP_SYS_OFFSET_PRECISE, &sys_off)) {
+    DEBUG_LOG("ioctl(%s) failed : %s", "PTP_SYS_OFFSET_PRECISE",
+              strerror(errno));
+    return 0;
+  }
+
+  phc_ts->tv_sec = sys_off.device.sec;
+  phc_ts->tv_nsec = sys_off.device.nsec;
+  sys_ts->tv_sec = sys_off.sys_realtime.sec;
+  sys_ts->tv_nsec = sys_off.sys_realtime.nsec;
+  *err = MAX(LCL_GetSysPrecisionAsQuantum(), precision);
+
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+/* ================================================== */
+
+int
+SYS_Linux_OpenPHC(const char *path, int phc_index)
+{
+  struct ptp_clock_caps caps;
+  char phc_path[64];
+  int phc_fd;
+
+  if (!path) {
+    if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
+      return -1;
+    path = phc_path;
+  }
+
+  phc_fd = open(path, O_RDONLY);
+  if (phc_fd < 0) {
+    LOG(LOGS_ERR, "Could not open %s : %s", path, strerror(errno));
+    return -1;
+  }
+
+  /* Make sure it is a PHC */
+  if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
+    LOG(LOGS_ERR, "ioctl(%s) failed : %s", "PTP_CLOCK_GETCAPS", strerror(errno));
+    close(phc_fd);
+    return -1;
+  }
+
+  UTI_FdSetCloexec(phc_fd);
+
+  return phc_fd;
+}
+
+/* ================================================== */
+
+int
+SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mode,
+                       struct timespec *phc_ts, struct timespec *sys_ts, double *err)
+{
+  if ((*reading_mode == 2 || !*reading_mode) && !nocrossts &&
+      get_precise_phc_sample(fd, precision, phc_ts, sys_ts, err)) {
+    *reading_mode = 2;
+    return 1;
+  } else if ((*reading_mode == 1 || !*reading_mode) &&
+      get_phc_sample(fd, precision, phc_ts, sys_ts, err)) {
+    *reading_mode = 1;
+    return 1;
+  }
+  return 0;
+}
+
+/* ================================================== */
+
+int
+SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel,
+                                int rising, int falling, int enable)
+{
+  struct ptp_extts_request extts_req;
+#ifdef PTP_PIN_SETFUNC
+  struct ptp_pin_desc pin_desc;
+
+  memset(&pin_desc, 0, sizeof (pin_desc));
+  pin_desc.index = pin;
+  pin_desc.func = enable ? PTP_PF_EXTTS : PTP_PF_NONE;
+  pin_desc.chan = channel;
+
+  if (ioctl(fd, PTP_PIN_SETFUNC, &pin_desc)) {
+    DEBUG_LOG("ioctl(%s) failed : %s", "PTP_PIN_SETFUNC", strerror(errno));
+    return 0;
+  }
+#else
+  DEBUG_LOG("Missing PTP_PIN_SETFUNC");
+  return 0;
+#endif
+
+  memset(&extts_req, 0, sizeof (extts_req));
+  extts_req.index = channel;
+  extts_req.flags = (enable ? PTP_ENABLE_FEATURE : 0) |
+                    (rising ? PTP_RISING_EDGE : 0) |
+                    (falling ? PTP_FALLING_EDGE : 0);
+
+  if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_req)) {
+    DEBUG_LOG("ioctl(%s) failed : %s", "PTP_EXTTS_REQUEST", strerror(errno));
+    return 0;
+  }
+
+  return 1;
+}
+
+/* ================================================== */
+
+int
+SYS_Linux_ReadPHCExtTimestamp(int fd, struct timespec *phc_ts, int *channel)
+{
+  struct ptp_extts_event extts_event;
+
+  if (read(fd, &extts_event, sizeof (extts_event)) != sizeof (extts_event)) {
+    DEBUG_LOG("Could not read PHC extts event");
+    return 0;
+  }
+
+  phc_ts->tv_sec = extts_event.t.sec;
+  phc_ts->tv_nsec = extts_event.t.nsec;
+  *channel = extts_event.index;
+
+  return 1;
+}
+
+#endif
diff --git a/chrony_3_3/sys_linux.h b/chrony_3_3/sys_linux.h
new file mode 100644
index 0000000..799ae9a
--- /dev/null
+++ b/chrony_3_3/sys_linux.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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  The header file for the linux driver
+  */
+
+#ifndef GOT_SYS_LINUX_H
+#define GOT_SYS_LINUX_H
+
+extern void SYS_Linux_Initialise(void);
+
+extern void SYS_Linux_Finalise(void);
+
+extern void SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control);
+
+extern void SYS_Linux_EnableSystemCallFilter(int level);
+
+extern void SYS_Linux_MemLockAll(int LockAll);
+
+extern void SYS_Linux_SetScheduler(int SchedPriority);
+
+extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor);
+
+extern int SYS_Linux_OpenPHC(const char *path, int phc_index);
+
+extern int SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mode,
+                                  struct timespec *phc_ts, struct timespec *sys_ts, double *err);
+
+extern int SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel,
+                                           int rising, int falling, int enable);
+
+extern int SYS_Linux_ReadPHCExtTimestamp(int fd, struct timespec *phc_ts, int *channel);
+
+#endif  /* GOT_SYS_LINUX_H */
diff --git a/chrony_3_3/sys_macosx.c b/chrony_3_3/sys_macosx.c
new file mode 100644
index 0000000..00ce302
--- /dev/null
+++ b/chrony_3_3/sys_macosx.c
@@ -0,0 +1,519 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2001
+ * Copyright (C) J. Hannken-Illjes  2001
+ * Copyright (C) Bryan Christianson  2015, 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.
+ *
+ **********************************************************************
+
+  =======================================================================
+
+  Driver file for the macOS operating system.
+
+  */
+
+#include "config.h"
+
+#ifdef MACOSX
+
+#include "sysincl.h"
+
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <pthread.h>
+
+#include "sys_macosx.h"
+#include "conf.h"
+#include "local.h"
+#include "localp.h"
+#include "logging.h"
+#include "sched.h"
+#include "privops.h"
+#include "util.h"
+
+#ifdef HAVE_MACOS_SYS_TIMEX
+#include <dlfcn.h>
+#include "sys_netbsd.h"
+#include "sys_timex.h"
+
+static int have_ntp_adjtime = 0;
+static int have_bad_adjtime = 0;
+#endif
+
+/* ================================================== */
+
+/* This register contains the number of seconds by which the local
+   clock was estimated to be fast of reference time at the epoch when
+   LCL_ReadRawTime() returned T0 */
+
+static double offset_register;
+
+/* This register contains the epoch to which the offset is referenced */
+
+static struct timespec T0;
+
+/* This register contains the current estimate of the system
+   frequency, in absolute (NOT ppm) */
+
+static double current_freq;
+
+/* This register contains the number of seconds of adjustment that
+   were passed to adjtime last time it was called. */
+
+static double adjustment_requested;
+
+/* Interval in seconds between adjustments to cancel systematic drift */
+
+#define DRIFT_REMOVAL_INTERVAL (4.0)
+#define DRIFT_REMOVAL_INTERVAL_MIN (0.5)
+
+/* If current_drift_removal_interval / drift_removal_interval exceeds this
+   ratio, then restart the drift removal timer */
+
+#define DRIFT_REMOVAL_RESTART_RATIO (8.0)
+
+static double drift_removal_interval;
+static double current_drift_removal_interval;
+static struct timespec Tdrift;
+
+/* weighting applied to error in calculating drift_removal_interval */
+#define ERROR_WEIGHT (0.5)
+
+/* minimum resolution of current_frequency */
+#define FREQUENCY_RES (1.0e-9)
+
+#define NANOS_PER_MSEC (1000000ULL)
+
+/* RTC synchronisation - once an hour */
+
+static struct timespec last_rtc_sync;
+#define RTC_SYNC_INTERVAL (60 * 60.0)
+
+/* ================================================== */
+
+static void
+clock_initialise(void)
+{
+  struct timeval newadj, oldadj;
+
+  offset_register = 0.0;
+  adjustment_requested = 0.0;
+  current_freq = 0.0;
+  drift_removal_interval = DRIFT_REMOVAL_INTERVAL;
+  current_drift_removal_interval = DRIFT_REMOVAL_INTERVAL;
+
+  LCL_ReadRawTime(&T0);
+  Tdrift = T0;
+  last_rtc_sync = T0;
+
+  newadj.tv_sec = 0;
+  newadj.tv_usec = 0;
+
+  if (PRV_AdjustTime(&newadj, &oldadj) < 0) {
+    LOG_FATAL("adjtime() failed");
+  }
+}
+
+/* ================================================== */
+
+static void
+clock_finalise(void)
+{
+  /* Nothing to do yet */
+}
+
+/* ================================================== */
+
+static void
+start_adjust(void)
+{
+  struct timeval newadj, oldadj;
+  struct timespec T1;
+  double elapsed, accrued_error, predicted_error, drift_removal_elapsed;
+  double adjust_required;
+  double rounding_error;
+  double old_adjust_remaining;
+
+  /* Determine the amount of error built up since the last adjustment */
+  LCL_ReadRawTime(&T1);
+
+  elapsed = UTI_DiffTimespecsToDouble(&T1, &T0);
+  accrued_error = elapsed * current_freq;
+
+  drift_removal_elapsed = UTI_DiffTimespecsToDouble(&T1, &Tdrift);
+
+  /* To allow for the clock being stepped either forward or backwards, clamp
+     the elapsed time to bounds [ 0.0, current_drift_removal_interval ] */
+  drift_removal_elapsed = MIN(MAX(0.0, drift_removal_elapsed), current_drift_removal_interval);
+
+  predicted_error = (current_drift_removal_interval - drift_removal_elapsed) / 2.0 * current_freq;
+
+  DEBUG_LOG("drift_removal_elapsed: %.3f current_drift_removal_interval: %.3f predicted_error: %.3f",
+            1.0e6 * drift_removal_elapsed, 1.0e6 * current_drift_removal_interval,
+            1.0e6 * predicted_error);
+
+  adjust_required = - (accrued_error + offset_register + predicted_error);
+
+  UTI_DoubleToTimeval(adjust_required, &newadj);
+  adjustment_requested = UTI_TimevalToDouble(&newadj);
+  rounding_error = adjust_required - adjustment_requested;
+
+  if (PRV_AdjustTime(&newadj, &oldadj) < 0) {
+    LOG_FATAL("adjtime() failed");
+  }
+
+  old_adjust_remaining = UTI_TimevalToDouble(&oldadj);
+
+  offset_register = rounding_error - old_adjust_remaining - predicted_error;
+
+  T0 = T1;
+}
+
+/* ================================================== */
+
+static void
+stop_adjust(void)
+{
+  struct timespec T1;
+  struct timeval zeroadj, remadj;
+  double adjustment_remaining, adjustment_achieved;
+  double elapsed, elapsed_plus_adjust;
+
+  zeroadj.tv_sec = 0;
+  zeroadj.tv_usec = 0;
+
+  if (PRV_AdjustTime(&zeroadj, &remadj) < 0) {
+    LOG_FATAL("adjtime() failed");
+  }
+
+  LCL_ReadRawTime(&T1);
+
+  elapsed = UTI_DiffTimespecsToDouble(&T1, &T0);
+  adjustment_remaining = UTI_TimevalToDouble(&remadj);
+
+  adjustment_achieved = adjustment_requested - adjustment_remaining;
+  elapsed_plus_adjust = elapsed - adjustment_achieved;
+
+  offset_register += current_freq * elapsed_plus_adjust - adjustment_remaining;
+
+  adjustment_requested = 0.0;
+  T0 = T1;
+}
+
+/* ================================================== */
+
+/* Positive offset means system clock is fast of true time, therefore
+   slew backwards */
+
+static void
+accrue_offset(double offset, double corr_rate)
+{
+  stop_adjust();
+  offset_register += offset;
+  start_adjust();
+}
+
+/* ================================================== */
+
+/* Positive offset means system clock is fast of true time, therefore
+   step backwards */
+
+static int
+apply_step_offset(double offset)
+{
+  struct timespec old_time, new_time, T1;
+  struct timeval new_time_tv;
+
+  stop_adjust();
+
+  LCL_ReadRawTime(&old_time);
+
+  UTI_AddDoubleToTimespec(&old_time, -offset, &new_time);
+  UTI_TimespecToTimeval(&new_time, &new_time_tv);
+
+  if (PRV_SetTime(&new_time_tv, NULL) < 0) {
+    DEBUG_LOG("settimeofday() failed");
+    return 0;
+  }
+
+  UTI_AddDoubleToTimespec(&T0, -offset, &T1);
+  T0 = T1;
+
+  start_adjust();
+
+  return 1;
+}
+
+/* ================================================== */
+
+static double
+set_frequency(double new_freq_ppm)
+{
+  stop_adjust();
+  current_freq = new_freq_ppm * 1.0e-6;
+  start_adjust();
+
+  return current_freq * 1.0e6;
+}
+
+/* ================================================== */
+
+static double
+read_frequency(void)
+{
+  return current_freq * 1.0e6;
+}
+
+/* ================================================== */
+
+static void
+get_offset_correction(struct timespec *raw,
+                      double *corr, double *err)
+{
+  stop_adjust();
+  *corr = -offset_register;
+  start_adjust();
+  if (err)
+    *err = 0.0;
+}
+
+/* ================================================== */
+
+/* Cancel systematic drift */
+
+static SCH_TimeoutID drift_removal_id;
+
+/* ================================================== */
+/* This is the timer callback routine which is called periodically to
+ invoke a time adjustment to take out the machine's drift.
+ Otherwise, times reported through this software (e.g. by running
+ ntpdate from another machine) show the machine being correct (since
+ they correct for drift build-up), but any program on this machine
+ that reads the system time will be given an erroneous value, the
+ degree of error depending on how long it is since
+ get_offset_correction was last called. */
+
+static void
+drift_removal_timeout(SCH_ArbitraryArgument not_used)
+{
+
+  stop_adjust();
+
+  LCL_ReadRawTime(&Tdrift);
+
+  current_drift_removal_interval = drift_removal_interval;
+
+  start_adjust();
+
+  drift_removal_id = SCH_AddTimeoutByDelay(drift_removal_interval, drift_removal_timeout, NULL);
+}
+
+/* ================================================== */
+
+/* use est_error to calculate the drift_removal_interval and
+   update the RTC */
+
+static void
+set_sync_status(int synchronised, double est_error, double max_error)
+{
+  double interval;
+
+  if (!synchronised) {
+    drift_removal_interval = MAX(drift_removal_interval, DRIFT_REMOVAL_INTERVAL);
+  } else {
+    if (CNF_GetRtcSync()) {
+      struct timespec now;
+      double rtc_sync_elapsed;
+
+      SCH_GetLastEventTime(NULL, NULL, &now);
+      rtc_sync_elapsed = UTI_DiffTimespecsToDouble(&now, &last_rtc_sync);
+      if (fabs(rtc_sync_elapsed) >= RTC_SYNC_INTERVAL) {
+        /* update the RTC by applying a step of 0.0 secs */
+        apply_step_offset(0.0);
+        last_rtc_sync = now;
+        DEBUG_LOG("rtc synchronised");
+      }
+    }
+
+    interval = ERROR_WEIGHT * est_error / (fabs(current_freq) + FREQUENCY_RES);
+    drift_removal_interval = MAX(interval, DRIFT_REMOVAL_INTERVAL_MIN);
+
+    DEBUG_LOG("est_error: %.3f current_freq: %.3f est drift_removal_interval: %.3f act drift_removal_interval: %.3f",
+                est_error * 1.0e6, current_freq * 1.0e6, interval, drift_removal_interval);
+  }
+
+  if (current_drift_removal_interval / drift_removal_interval > DRIFT_REMOVAL_RESTART_RATIO) {
+    /* recover from a large est_error by resetting the timer */
+    SCH_ArbitraryArgument unused;
+    SCH_RemoveTimeout(drift_removal_id);
+    unused = NULL;
+    drift_removal_timeout(unused);
+  }
+}
+
+/* ================================================== */
+/*
+  Give chronyd real time priority so that time critical calculations
+  are not pre-empted by the kernel.
+*/
+
+static int
+set_realtime(void)
+{
+  /* https://developer.apple.com/library/ios/technotes/tn2169/_index.html */
+
+  mach_timebase_info_data_t timebase_info;
+  double clock2abs;
+  thread_time_constraint_policy_data_t policy;
+  int kr;
+
+  mach_timebase_info(&timebase_info);
+  clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
+
+  policy.period = 0;
+  policy.computation = (uint32_t)(5 * clock2abs); /* 5 ms of work */
+  policy.constraint = (uint32_t)(10 * clock2abs);
+  policy.preemptible = 0;
+
+  kr = thread_policy_set(
+          pthread_mach_thread_np(pthread_self()),
+          THREAD_TIME_CONSTRAINT_POLICY,
+          (thread_policy_t)&policy,
+          THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+
+  if (kr != KERN_SUCCESS) {
+    LOG(LOGS_WARN, "Cannot set real-time priority: %d", kr);
+    return -1;
+  }
+  return 0;
+}
+
+/* ================================================== */
+
+void
+SYS_MacOSX_SetScheduler(int SchedPriority)
+{
+  if (SchedPriority) {
+    set_realtime();
+  }
+}
+
+/* ================================================== */
+
+#ifdef FEAT_PRIVDROP
+void SYS_MacOSX_DropRoot(uid_t uid, gid_t gid)
+{
+  PRV_StartHelper();
+
+  UTI_DropRoot(uid, gid);
+}
+#endif
+
+/* ================================================== */
+
+static void
+legacy_MacOSX_Initialise(void)
+{
+  clock_initialise();
+
+  lcl_RegisterSystemDrivers(read_frequency, set_frequency,
+                            accrue_offset, apply_step_offset,
+                            get_offset_correction,
+                            NULL /* set_leap */,
+                            set_sync_status);
+
+
+  drift_removal_id = SCH_AddTimeoutByDelay(drift_removal_interval, drift_removal_timeout, NULL);
+}
+
+/* ================================================== */
+
+static void
+legacy_MacOSX_Finalise(void)
+{
+  SCH_RemoveTimeout(drift_removal_id);
+
+  clock_finalise();
+}
+
+/* ================================================== */
+
+#ifdef HAVE_MACOS_SYS_TIMEX
+/*
+    Test adjtime() to see if Apple have fixed the signed/unsigned bug
+*/
+static int
+test_adjtime()
+{
+  struct timeval tv1 = {-1, 0};
+  struct timeval tv2 = {0, 0};
+  struct timeval tv;
+
+  if (PRV_AdjustTime(&tv1, &tv) != 0) {
+    return 0;
+  }
+  if (PRV_AdjustTime(&tv2, &tv) != 0) {
+    return 0;
+  }
+  if (tv.tv_sec < -1 || tv.tv_sec > 1) {
+    return 0;
+  }
+  return 1;
+}
+#endif
+
+/* ================================================== */
+
+void
+SYS_MacOSX_Initialise(void)
+{
+#ifdef HAVE_MACOS_SYS_TIMEX
+  have_ntp_adjtime = (dlsym(RTLD_NEXT, "ntp_adjtime") != NULL);
+  if (have_ntp_adjtime) {
+    have_bad_adjtime = !test_adjtime();
+    if (have_bad_adjtime) {
+      LOG(LOGS_WARN, "adjtime() is buggy - using timex driver");
+      SYS_Timex_Initialise();
+    } else {
+      SYS_NetBSD_Initialise();
+    }
+    return;
+  }
+#endif
+  legacy_MacOSX_Initialise();
+}
+
+/* ================================================== */
+
+void
+SYS_MacOSX_Finalise(void)
+{
+#ifdef HAVE_MACOS_SYS_TIMEX
+  if (have_ntp_adjtime) {
+    if (have_bad_adjtime) {
+      SYS_Timex_Finalise();
+    } else {
+      SYS_NetBSD_Finalise();
+    }
+    return;
+  }
+#endif
+  legacy_MacOSX_Finalise();
+}
+
+#endif
diff --git a/chrony_3_3/sys_macosx.h b/chrony_3_3/sys_macosx.h
new file mode 100644
index 0000000..5555616
--- /dev/null
+++ b/chrony_3_3/sys_macosx.h
@@ -0,0 +1,38 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2001
+ * Copyright (C) J. Hannken-Illjes  2001
+ * Copyright (C) Bryan Christianson 2015
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ **********************************************************************
+
+  =======================================================================
+
+  Header file for macOS driver
+
+  */
+
+#ifndef GOT_SYS_MACOSX_H
+#define GOT_SYS_MACOSX_H
+
+void SYS_MacOSX_SetScheduler(int SchedPriority);
+void SYS_MacOSX_DropRoot(uid_t uid, gid_t gid);
+void SYS_MacOSX_Initialise(void);
+void SYS_MacOSX_Finalise(void);
+
+#endif
diff --git a/chrony_3_3/sys_netbsd.c b/chrony_3_3/sys_netbsd.c
new file mode 100644
index 0000000..840d6a5
--- /dev/null
+++ b/chrony_3_3/sys_netbsd.c
@@ -0,0 +1,154 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2001
+ * Copyright (C) J. Hannken-Illjes  2001
+ * Copyright (C) Miroslav Lichvar  2015
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Driver file for the NetBSD and FreeBSD operating system.
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "sys_netbsd.h"
+#include "sys_timex.h"
+#include "logging.h"
+#include "privops.h"
+#include "util.h"
+
+/* Maximum frequency offset accepted by the kernel (in ppm) */
+#define MAX_FREQ 500.0
+
+/* Minimum assumed rate at which the kernel updates the clock frequency */
+#define MIN_TICK_RATE 100
+
+/* Interval between kernel updates of the adjtime() offset */
+#define ADJTIME_UPDATE_INTERVAL 1.0
+
+/* Maximum adjtime() slew rate (in ppm) */
+#define MAX_ADJTIME_SLEWRATE 5000.0
+
+/* Minimum offset adjtime() slews faster than MAX_FREQ */
+#define MIN_FASTSLEW_OFFSET 1.0
+
+/* ================================================== */
+
+/* Positive offset means system clock is fast of true time, therefore
+   slew backwards */
+
+static void
+accrue_offset(double offset, double corr_rate)
+{
+  struct timeval newadj, oldadj;
+  double doldadj;
+
+  UTI_DoubleToTimeval(-offset, &newadj);
+
+  if (PRV_AdjustTime(&newadj, &oldadj) < 0)
+    LOG_FATAL("adjtime() failed");
+
+  /* Add the old remaining adjustment if not zero */
+  doldadj = UTI_TimevalToDouble(&oldadj);
+  if (doldadj != 0.0) {
+    UTI_DoubleToTimeval(-offset + doldadj, &newadj);
+    if (PRV_AdjustTime(&newadj, NULL) < 0)
+      LOG_FATAL("adjtime() failed");
+  }
+}
+
+/* ================================================== */
+
+static void
+get_offset_correction(struct timespec *raw,
+                      double *corr, double *err)
+{
+  struct timeval remadj;
+  double adjustment_remaining;
+#ifdef MACOSX
+  struct timeval tv = {0, 0};
+
+  if (PRV_AdjustTime(&tv, &remadj) < 0)
+    LOG_FATAL("adjtime() failed");
+
+  if (PRV_AdjustTime(&remadj, NULL) < 0)
+    LOG_FATAL("adjtime() failed");
+#else
+  if (PRV_AdjustTime(NULL, &remadj) < 0)
+    LOG_FATAL("adjtime() failed");
+#endif
+
+  adjustment_remaining = UTI_TimevalToDouble(&remadj);
+
+  *corr = adjustment_remaining;
+  if (err) {
+    if (*corr != 0.0)
+      *err = 1.0e-6 * MAX_ADJTIME_SLEWRATE / ADJTIME_UPDATE_INTERVAL;
+    else
+      *err = 0.0;
+  }
+}
+
+/* ================================================== */
+
+void
+SYS_NetBSD_Initialise(void)
+{
+  SYS_Timex_InitialiseWithFunctions(MAX_FREQ, 1.0 / MIN_TICK_RATE,
+                                    NULL, NULL, NULL,
+                                    MIN_FASTSLEW_OFFSET, MAX_ADJTIME_SLEWRATE,
+                                    accrue_offset, get_offset_correction);
+}
+
+/* ================================================== */
+
+void
+SYS_NetBSD_Finalise(void)
+{
+  SYS_Timex_Finalise();
+}
+
+/* ================================================== */
+
+#ifdef FEAT_PRIVDROP
+void
+SYS_NetBSD_DropRoot(uid_t uid, gid_t gid)
+{
+#ifdef NETBSD
+  int fd;
+#endif
+
+  /* On NetBSD the helper is used only for socket binding, but on FreeBSD
+     it's used also for setting and adjusting the system clock */
+  PRV_StartHelper();
+
+  UTI_DropRoot(uid, gid);
+
+#ifdef NETBSD
+  /* Check if we have write access to /dev/clockctl */
+  fd = open("/dev/clockctl", O_WRONLY);
+  if (fd < 0)
+    LOG_FATAL("Can't write to /dev/clockctl");
+  close(fd);
+#endif
+}
+#endif
diff --git a/chrony_3_3/sys_netbsd.h b/chrony_3_3/sys_netbsd.h
new file mode 100644
index 0000000..052f5b7
--- /dev/null
+++ b/chrony_3_3/sys_netbsd.h
@@ -0,0 +1,37 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2001
+ * Copyright (C) J. Hannken-Illjes  2001
+ * 
+ * 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 NetBSD driver
+  */
+
+#ifndef GOT_SYS_NETBSD_H
+#define GOT_SYS_NETBSD_H
+
+void SYS_NetBSD_Initialise(void);
+
+void SYS_NetBSD_Finalise(void);
+
+void SYS_NetBSD_DropRoot(uid_t uid, gid_t gid);
+
+#endif
diff --git a/chrony_3_3/sys_null.c b/chrony_3_3/sys_null.c
new file mode 100644
index 0000000..3a0d5f6
--- /dev/null
+++ b/chrony_3_3/sys_null.c
@@ -0,0 +1,140 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Null clock driver for operation with no clock control.
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "sys_null.h"
+
+#include "local.h"
+#include "localp.h"
+#include "logging.h"
+#include "util.h"
+
+/* Current frequency offset of the system clock (in ppm) */
+static double freq;
+
+/* Offset of the system clock at the last update */
+static double offset_register;
+
+/* Time of the last update */
+static struct timespec last_update;
+
+/* Minimum interval between updates when frequency is constant */
+#define MIN_UPDATE_INTERVAL 1000.0
+
+/* ================================================== */
+
+static void
+update_offset(void)
+{
+  struct timespec now;
+  double duration;
+
+  LCL_ReadRawTime(&now);
+  duration = UTI_DiffTimespecsToDouble(&now, &last_update);
+  offset_register += 1.0e-6 * freq * duration;
+  last_update = now;
+
+  DEBUG_LOG("System clock offset=%e freq=%f", offset_register, freq);
+}
+
+/* ================================================== */
+
+static double
+read_frequency(void)
+{
+  return freq;
+}
+
+/* ================================================== */
+
+static double
+set_frequency(double freq_ppm)
+{
+  update_offset();
+  freq = freq_ppm;
+
+  return freq;
+}
+
+/* ================================================== */
+
+static void
+accrue_offset(double offset, double corr_rate)
+{
+  offset_register += offset;
+}
+
+/* ================================================== */
+
+static int
+apply_step_offset(double offset)
+{
+  return 0;
+}
+
+/* ================================================== */
+
+static void
+offset_convert(struct timespec *raw, double *corr, double *err)
+{
+  double duration;
+
+  duration = UTI_DiffTimespecsToDouble(raw, &last_update);
+
+  if (duration > MIN_UPDATE_INTERVAL) {
+    update_offset();
+    duration = 0.0;
+  }
+
+  *corr = -1.0e-6 * freq * duration - offset_register;
+
+  if (err)
+    *err = 0.0;
+}
+
+/* ================================================== */
+
+void
+SYS_Null_Initialise(void)
+{
+  offset_register = 0.0;
+  LCL_ReadRawTime(&last_update);
+
+  lcl_RegisterSystemDrivers(read_frequency, set_frequency, accrue_offset,
+                            apply_step_offset, offset_convert, NULL, NULL);
+
+  LOG(LOGS_INFO, "Disabled control of system clock");
+}
+
+/* ================================================== */
+
+void
+SYS_Null_Finalise(void)
+{
+}
diff --git a/chrony_3_3/sys_null.h b/chrony_3_3/sys_null.h
new file mode 100644
index 0000000..0fbf077
--- /dev/null
+++ b/chrony_3_3/sys_null.h
@@ -0,0 +1,34 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Header file for null clock driver
+  */
+
+#ifndef GOT_SYS_NULL_H
+#define GOT_SYS_NULL_H
+
+extern void SYS_Null_Initialise(void);
+
+extern void SYS_Null_Finalise(void);
+
+#endif
diff --git a/chrony_3_3/sys_solaris.c b/chrony_3_3/sys_solaris.c
new file mode 100644
index 0000000..21197b9
--- /dev/null
+++ b/chrony_3_3/sys_solaris.c
@@ -0,0 +1,63 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Driver file for Solaris operating system
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "privops.h"
+#include "sys_solaris.h"
+#include "sys_timex.h"
+#include "util.h"
+
+/* ================================================== */
+
+void
+SYS_Solaris_Initialise(void)
+{
+  /* The kernel allows the frequency to be set in the full range off int32_t */
+  SYS_Timex_InitialiseWithFunctions(32500, 1.0 / 100, NULL, NULL, NULL,
+                                    0.0, 0.0, NULL, NULL);
+}
+
+/* ================================================== */
+
+void
+SYS_Solaris_Finalise(void)
+{
+  SYS_Timex_Finalise();
+}
+
+/* ================================================== */
+
+#ifdef FEAT_PRIVDROP
+void
+SYS_Solaris_DropRoot(uid_t uid, gid_t gid)
+{
+  PRV_StartHelper();
+  UTI_DropRoot(uid, gid);
+}
+#endif
diff --git a/chrony_3_3/sys_solaris.h b/chrony_3_3/sys_solaris.h
new file mode 100644
index 0000000..46015ba
--- /dev/null
+++ b/chrony_3_3/sys_solaris.h
@@ -0,0 +1,36 @@
+/*
+  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 Solaris driver
+  */
+
+#ifndef GOT_SYS_SOLARIS_H
+#define GOT_SYS_SOLARIS_H
+
+void SYS_Solaris_Initialise(void);
+
+void SYS_Solaris_Finalise(void);
+
+void SYS_Solaris_DropRoot(uid_t uid, gid_t gid);
+
+#endif
diff --git a/chrony_3_3/sys_timex.c b/chrony_3_3/sys_timex.c
new file mode 100644
index 0000000..e54ad24
--- /dev/null
+++ b/chrony_3_3/sys_timex.c
@@ -0,0 +1,266 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2009-2012, 2014-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Driver for systems that implement the adjtimex()/ntp_adjtime() system call
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "conf.h"
+#include "privops.h"
+#include "sys_generic.h"
+#include "sys_timex.h"
+#include "logging.h"
+
+#ifdef PRIVOPS_ADJUSTTIMEX
+#define NTP_ADJTIME PRV_AdjustTimex
+#define NTP_ADJTIME_NAME "ntp_adjtime"
+#else
+#ifdef LINUX
+#define NTP_ADJTIME adjtimex
+#define NTP_ADJTIME_NAME "adjtimex"
+#else
+#define NTP_ADJTIME ntp_adjtime
+#define NTP_ADJTIME_NAME "ntp_adjtime"
+#endif
+#endif
+
+/* Maximum frequency offset accepted by the kernel (in ppm) */
+#define MAX_FREQ 500.0
+
+/* Frequency scale to convert from ppm to the timex freq */
+#define FREQ_SCALE (double)(1 << 16)
+
+/* Threshold for the timex maxerror when the kernel sets the UNSYNC flag */
+#define MAX_SYNC_ERROR 16.0
+
+/* Minimum assumed rate at which the kernel updates the clock frequency */
+#define MIN_TICK_RATE 100
+
+/* Saved timex status */
+static int sys_status;
+
+/* Saved TAI-UTC offset */
+static int sys_tai_offset;
+
+/* ================================================== */
+
+static double
+read_frequency(void)
+{
+  struct timex txc;
+
+  txc.modes = 0;
+
+  SYS_Timex_Adjust(&txc, 0);
+
+  return txc.freq / -FREQ_SCALE;
+}
+
+/* ================================================== */
+
+static double
+set_frequency(double freq_ppm)
+{
+  struct timex txc;
+
+  txc.modes = MOD_FREQUENCY;
+  txc.freq = freq_ppm * -FREQ_SCALE;
+
+  SYS_Timex_Adjust(&txc, 0);
+
+  return txc.freq / -FREQ_SCALE;
+}
+
+/* ================================================== */
+
+static void
+set_leap(int leap, int tai_offset)
+{
+  struct timex txc;
+  int applied, prev_status;
+
+  txc.modes = 0;
+  applied = SYS_Timex_Adjust(&txc, 0) == TIME_WAIT;
+
+  prev_status = sys_status;
+  sys_status &= ~(STA_INS | STA_DEL);
+
+  if (leap > 0)
+    sys_status |= STA_INS;
+  else if (leap < 0)
+    sys_status |= STA_DEL;
+
+  txc.modes = MOD_STATUS;
+  txc.status = sys_status;
+
+#ifdef MOD_TAI
+  if (tai_offset) {
+    txc.modes |= MOD_TAI;
+    txc.constant = tai_offset;
+
+    if (applied && !(sys_status & (STA_INS | STA_DEL)))
+      sys_tai_offset += prev_status & STA_INS ? 1 : -1;
+
+    if (sys_tai_offset != tai_offset) {
+      sys_tai_offset = tai_offset;
+      LOG(LOGS_INFO, "System clock TAI offset set to %d seconds", tai_offset);
+    }
+  }
+#endif
+
+  SYS_Timex_Adjust(&txc, 0);
+
+  if (prev_status != sys_status) {
+    LOG(LOGS_INFO, "System clock status %s leap second",
+        leap ? (leap > 0 ? "set to insert" : "set to delete") :
+        (applied ? "reset after" : "set to not insert/delete"));
+  }
+}
+
+/* ================================================== */
+
+static void
+set_sync_status(int synchronised, double est_error, double max_error)
+{
+  struct timex txc;
+
+  if (synchronised) {
+    if (est_error > MAX_SYNC_ERROR)
+      est_error = MAX_SYNC_ERROR;
+    if (max_error >= MAX_SYNC_ERROR) {
+      max_error = MAX_SYNC_ERROR;
+      synchronised = 0;
+    }
+  } else {
+    est_error = max_error = MAX_SYNC_ERROR;
+  }
+
+#ifdef LINUX
+  /* On Linux clear the UNSYNC flag only if rtcsync is enabled */
+  if (!CNF_GetRtcSync())
+    synchronised = 0;
+#endif
+
+  if (synchronised)
+    sys_status &= ~STA_UNSYNC;
+  else
+    sys_status |= STA_UNSYNC;
+
+  txc.modes = MOD_STATUS | MOD_ESTERROR | MOD_MAXERROR;
+  txc.status = sys_status;
+  txc.esterror = est_error * 1.0e6;
+  txc.maxerror = max_error * 1.0e6;
+
+  if (SYS_Timex_Adjust(&txc, 1) < 0)
+    ;
+}
+
+/* ================================================== */
+
+static void
+initialise_timex(void)
+{
+  struct timex txc;
+
+  sys_status = STA_UNSYNC;
+  sys_tai_offset = 0;
+
+  /* Reset PLL offset */
+  txc.modes = MOD_OFFSET | MOD_STATUS;
+  txc.status = STA_PLL | sys_status;
+  txc.offset = 0;
+  SYS_Timex_Adjust(&txc, 0);
+
+  /* Turn PLL off */
+  txc.modes = MOD_STATUS;
+  txc.status = sys_status;
+  SYS_Timex_Adjust(&txc, 0);
+}
+
+/* ================================================== */
+
+void
+SYS_Timex_Initialise(void)
+{
+  SYS_Timex_InitialiseWithFunctions(MAX_FREQ, 1.0 / MIN_TICK_RATE, NULL, NULL, NULL,
+                                    0.0, 0.0, NULL, NULL);
+}
+
+/* ================================================== */
+
+void
+SYS_Timex_InitialiseWithFunctions(double max_set_freq_ppm, double max_set_freq_delay,
+                                  lcl_ReadFrequencyDriver sys_read_freq,
+                                  lcl_SetFrequencyDriver sys_set_freq,
+                                  lcl_ApplyStepOffsetDriver sys_apply_step_offset,
+                                  double min_fastslew_offset, double max_fastslew_rate,
+                                  lcl_AccrueOffsetDriver sys_accrue_offset,
+                                  lcl_OffsetCorrectionDriver sys_get_offset_correction)
+{
+  initialise_timex();
+
+  SYS_Generic_CompleteFreqDriver(max_set_freq_ppm, max_set_freq_delay,
+                                 sys_read_freq ? sys_read_freq : read_frequency,
+                                 sys_set_freq ? sys_set_freq : set_frequency,
+                                 sys_apply_step_offset,
+                                 min_fastslew_offset, max_fastslew_rate,
+                                 sys_accrue_offset, sys_get_offset_correction,
+                                 set_leap, set_sync_status);
+}
+
+/* ================================================== */
+
+void
+SYS_Timex_Finalise(void)
+{
+  SYS_Generic_Finalise();
+}
+
+/* ================================================== */
+
+int
+SYS_Timex_Adjust(struct timex *txc, int ignore_error)
+{
+  int state;
+
+#ifdef SOLARIS
+  /* The kernel seems to check the constant even when it's not being set */
+  if (!(txc->modes & MOD_TIMECONST))
+    txc->constant = 10;
+#endif
+
+  state = NTP_ADJTIME(txc);
+
+  if (state < 0) {
+    if (!ignore_error)
+      LOG_FATAL(NTP_ADJTIME_NAME"(0x%x) failed : %s", txc->modes, strerror(errno));
+    else
+      DEBUG_LOG(NTP_ADJTIME_NAME"(0x%x) failed : %s", txc->modes, strerror(errno));
+  }
+
+  return state;
+}
diff --git a/chrony_3_3/sys_timex.h b/chrony_3_3/sys_timex.h
new file mode 100644
index 0000000..b8617a2
--- /dev/null
+++ b/chrony_3_3/sys_timex.h
@@ -0,0 +1,48 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2015
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Header file for a driver based on the adjtimex()/ntp_adjtime() function
+  */
+
+#ifndef GOT_SYS_TIMEX_H
+#define GOT_SYS_TIMEX_H
+
+#include "localp.h"
+
+extern void SYS_Timex_Initialise(void);
+
+/* Initialise with some driver functions replaced with special versions */
+extern void SYS_Timex_InitialiseWithFunctions(double max_set_freq_ppm, double max_set_freq_delay,
+                                              lcl_ReadFrequencyDriver sys_read_freq,
+                                              lcl_SetFrequencyDriver sys_set_freq,
+                                              lcl_ApplyStepOffsetDriver sys_apply_step_offset,
+                                              double min_fastslew_offset, double max_fastslew_rate,
+                                              lcl_AccrueOffsetDriver sys_accrue_offset,
+                                              lcl_OffsetCorrectionDriver sys_get_offset_correction);
+
+extern void SYS_Timex_Finalise(void);
+
+/* Wrapper for adjtimex()/ntp_adjtime() */
+extern int SYS_Timex_Adjust(struct timex *txc, int ignore_error);
+
+#endif  /* GOT_SYS_GENERIC_H */
diff --git a/chrony_3_3/sysincl.h b/chrony_3_3/sysincl.h
new file mode 100644
index 0000000..a9e4da0
--- /dev/null
+++ b/chrony_3_3/sysincl.h
@@ -0,0 +1,83 @@
+/*
+  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 file includes all system header files that the software
+  requires.  This allows us to isolate system dependencies to this file
+  alone.
+  */
+
+#ifndef GOT_SYSINCL_H
+#define GOT_SYSINCL_H
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <float.h>
+#include <glob.h>
+#include <grp.h>
+#include <math.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <pwd.h>
+#include <resolv.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#if defined(LINUX) || defined(FREEBSD) || defined(NETBSD) || defined(SOLARIS) || defined(HAVE_MACOS_SYS_TIMEX)
+#include <sys/timex.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#elif HAVE_STDINT_H
+#include <stdint.h>
+#else
+/* Tough */
+#endif
+
+#ifdef FEAT_IPV6
+/* For inet_ntop() */
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_GETRANDOM
+#include <sys/random.h>
+#endif
+
+#endif /* GOT_SYSINCL_H */
diff --git a/chrony_3_3/tempcomp.c b/chrony_3_3/tempcomp.c
new file mode 100644
index 0000000..f57e5cc
--- /dev/null
+++ b/chrony_3_3/tempcomp.c
@@ -0,0 +1,180 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2011, 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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Routines implementing temperature compensation.
+
+  */
+
+#include "config.h"
+
+#include "array.h"
+#include "conf.h"
+#include "local.h"
+#include "memory.h"
+#include "util.h"
+#include "logging.h"
+#include "sched.h"
+#include "tempcomp.h"
+
+/* Sanity limit (in ppm) */
+#define MAX_COMP 10.0
+
+static SCH_TimeoutID timeout_id;
+
+static LOG_FileID logfileid;
+
+static char *filename;
+static double update_interval;
+static double T0, k0, k1, k2;
+
+struct Point {
+  double temp;
+  double comp;
+};
+
+static ARR_Instance points;
+
+static double
+get_tempcomp(double temp)
+{
+  unsigned int i;
+  struct Point *p1 = NULL, *p2 = NULL;
+
+  /* If not configured with points, calculate the compensation from the
+     specified quadratic function */
+  if (!points)
+    return k0 + (temp - T0) * k1 + (temp - T0) * (temp - T0) * k2;
+
+  /* Otherwise interpolate/extrapolate between two nearest points */
+
+  for (i = 1; i < ARR_GetSize(points); i++) {
+    p2 = (struct Point *)ARR_GetElement(points, i);
+    if (p2->temp >= temp)
+      break;
+  }
+  p1 = p2 - 1;
+
+  return (temp - p1->temp) / (p2->temp - p1->temp) *
+         (p2->comp - p1->comp) + p1->comp;
+}
+
+static void
+read_timeout(void *arg)
+{
+  FILE *f;
+  double temp, comp;
+
+  f = fopen(filename, "r");
+
+  if (f && fscanf(f, "%lf", &temp) == 1) {
+    comp = get_tempcomp(temp);
+
+    if (fabs(comp) <= MAX_COMP) {
+      comp = LCL_SetTempComp(comp);
+
+      DEBUG_LOG("tempcomp updated to %f for %f", comp, temp);
+
+      if (logfileid != -1) {
+        struct timespec now;
+
+        LCL_ReadCookedTime(&now, NULL);
+        LOG_FileWrite(logfileid, "%s %11.4e %11.4e",
+            UTI_TimeToLogForm(now.tv_sec), temp, comp);
+      }
+    } else {
+      LOG(LOGS_WARN, "Temperature compensation of %.3f ppm exceeds sanity limit of %.1f",
+          comp, MAX_COMP);
+    }
+  } else {
+    LOG(LOGS_WARN, "Could not read temperature from %s", filename);
+  }
+
+  if (f)
+    fclose(f);
+
+  timeout_id = SCH_AddTimeoutByDelay(update_interval, read_timeout, NULL);
+}
+
+static void
+read_points(const char *filename)
+{
+  FILE *f;
+  char line[256];
+  struct Point *p;
+
+  f = fopen(filename, "r");
+  if (!f) {
+    LOG_FATAL("Could not open tempcomp point file %s", filename);
+    return;
+  }
+
+  points = ARR_CreateInstance(sizeof (struct Point));
+
+  while (fgets(line, sizeof (line), f)) {
+    p = (struct Point *)ARR_GetNewElement(points);
+    if (sscanf(line, "%lf %lf", &p->temp, &p->comp) != 2) {
+      LOG_FATAL("Could not read tempcomp point from %s", filename);
+      break;
+    }
+  }
+
+  fclose(f);
+
+  if (ARR_GetSize(points) < 2)
+    LOG_FATAL("Not enough points in %s", filename);
+}
+
+void
+TMC_Initialise(void)
+{
+  char *point_file;
+
+  CNF_GetTempComp(&filename, &update_interval, &point_file, &T0, &k0, &k1, &k2);
+
+  if (filename == NULL)
+    return;
+
+  if (update_interval <= 0.0)
+    update_interval = 1.0;
+
+  if (point_file)
+    read_points(point_file);
+
+  logfileid = CNF_GetLogTempComp() ? LOG_FileOpen("tempcomp",
+      "   Date (UTC) Time        Temp.       Comp.")
+    : -1;
+
+  read_timeout(NULL);
+}
+
+void
+TMC_Finalise(void)
+{
+  if (filename == NULL)
+    return;
+
+  if (points)
+    ARR_DestroyInstance(points);
+
+  SCH_RemoveTimeout(timeout_id);
+}
diff --git a/chrony_3_3/tempcomp.h b/chrony_3_3/tempcomp.h
new file mode 100644
index 0000000..b876f90
--- /dev/null
+++ b/chrony_3_3/tempcomp.h
@@ -0,0 +1,29 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2011
+ * 
+ * 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 temperature compensation.
+
+  */
+
+extern void TMC_Initialise(void);
+extern void TMC_Finalise(void);
diff --git a/chrony_3_3/test/compilation/001-features b/chrony_3_3/test/compilation/001-features
new file mode 100755
index 0000000..d61c07f
--- /dev/null
+++ b/chrony_3_3/test/compilation/001-features
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# Try to compile chrony in various combinations of disabled features
+
+cd ../..
+
+for opts in \
+	"--enable-debug" \
+	"--enable-ntp-signd" \
+	"--enable-scfilter" \
+	"--disable-asyncdns" \
+	"--disable-ipv6" \
+	"--disable-privdrop" \
+	"--disable-readline" \
+	"--disable-rtc" \
+	"--disable-sechash" \
+	"--disable-cmdmon" \
+	"--disable-ntp" \
+	"--disable-refclock" \
+	"--disable-timestamping" \
+	"--disable-timestamping --disable-ntp" \
+	"--disable-cmdmon --disable-ntp" \
+	"--disable-cmdmon --disable-refclock" \
+	"--disable-cmdmon --disable-ntp --disable-refclock"
+do
+	./configure $opts
+	make "$@" || exit 1
+done
diff --git a/chrony_3_3/test/compilation/002-scanbuild b/chrony_3_3/test/compilation/002-scanbuild
new file mode 100755
index 0000000..da87407
--- /dev/null
+++ b/chrony_3_3/test/compilation/002-scanbuild
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+cd ../..
+
+for opts in \
+	"--host-system=Linux" \
+	"--host-system=NetBSD" \
+	"--host-system=FreeBSD" \
+	"--without-nettle" \
+	"--without-nettle --without-nss" \
+	"--without-nettle --without-nss --without-tomcrypt"
+do
+	./configure $opts
+	scan-build make "$@" || exit 1
+done
diff --git a/chrony_3_3/test/kernel/Makefile b/chrony_3_3/test/kernel/Makefile
new file mode 100644
index 0000000..6ec8341
--- /dev/null
+++ b/chrony_3_3/test/kernel/Makefile
@@ -0,0 +1,7 @@
+CFLAGS=-O2 -Wall
+PROGS=adjtime ntpadjtime
+
+all: $(PROGS)
+
+clean:
+	rm -f $(PROGS)
diff --git a/chrony_3_3/test/kernel/adjtime.c b/chrony_3_3/test/kernel/adjtime.c
new file mode 100644
index 0000000..0ca8ff2
--- /dev/null
+++ b/chrony_3_3/test/kernel/adjtime.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) Miroslav Lichvar  2015
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/* Test the system adjtime() function. Check the range of supported offset,
+   support for readonly operation, and slew rate with different update
+   intervals and offsets. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+static int
+diff_tv(struct timeval *tv1, struct timeval *tv2)
+{
+  return 1000000 * (tv1->tv_sec - tv2->tv_sec) + (tv1->tv_usec - tv2->tv_usec);
+}
+
+static struct timeval
+usec_to_tv(int usec)
+{
+  struct timeval tv;
+
+  tv.tv_sec = usec / 1000000;
+  tv.tv_usec = usec % 1000000;
+
+  return tv;
+}
+
+static int
+try_adjtime(struct timeval *new, struct timeval *old)
+{
+  int r;
+
+  r = adjtime(new, old);
+  if (r)
+    printf("adjtime() failed : %s ", strerror(errno));
+  return r;
+}
+
+static void
+reset_adjtime(void)
+{
+  struct timeval tv;
+
+  tv = usec_to_tv(0);
+  try_adjtime(&tv, NULL);
+}
+
+static void
+test_range(void)
+{
+  struct timeval tv;
+  int i;
+
+  printf("range:\n");
+
+  for (i = 0; i < sizeof (time_t) * 8; i++) {
+    tv.tv_usec = 0;
+    tv.tv_sec = (1ULL << i) - 1;
+    printf("%20lld s : ", (long long)tv.tv_sec);
+    printf("%s\n", !try_adjtime(&tv, NULL) ? "ok" : "");
+    tv.tv_sec = ~tv.tv_sec;
+    printf("%20lld s : ", (long long)tv.tv_sec);
+    printf("%s\n", !try_adjtime(&tv, NULL) ? "ok" : "");
+  }
+}
+
+static void
+test_readonly(void)
+{
+  struct timeval tv1, tv2;
+  int i, r;
+
+  printf("readonly:\n");
+
+  for (i = 0; i <= 20; i++) {
+    tv1 = usec_to_tv(1 << i);
+
+    printf("%9d us : ", 1 << i);
+    try_adjtime(&tv1, NULL);
+    r = !try_adjtime(NULL, &tv2) && !diff_tv(&tv1, &tv2);
+    printf("%s\n", r ? "ok" : "fail");
+  }
+}
+
+static void
+test_readwrite(void)
+{
+  struct timeval tv1, tv2, tv3;
+  int i, r;
+
+  printf("readwrite:\n");
+
+  for (i = 0; i <= 20; i++) {
+    tv1 = usec_to_tv(1 << i);
+    tv3 = usec_to_tv(0);
+
+    printf("%9d us : ", 1 << i);
+    try_adjtime(&tv1, NULL);
+    r = !try_adjtime(&tv3, &tv2) && !diff_tv(&tv1, &tv2);
+    printf("%s\n", r ? "ok" : "fail");
+  }
+}
+
+static void
+xusleep(int usec)
+{
+  struct timeval tv;
+
+  tv = usec_to_tv(usec);
+  select(0, NULL, NULL, NULL, &tv);
+}
+
+static void
+test_slew(void)
+{
+  struct timeval tv1, tv2, tv3;
+  int i, j, k, diff, min, has_min;
+
+  printf("slew:\n");
+
+  for (i = 9; i <= 20; i++) {
+    printf("%9d us : ", 1 << i);
+    for (j = 4; j <= 20; j += 4) {
+      for (min = has_min = 0, k = 4; k < 16; k += 2) {
+
+        tv1 = usec_to_tv(1 << j);
+        tv3 = usec_to_tv(0);
+
+        xusleep(1 << i);
+        reset_adjtime();
+
+        xusleep(1 << i);
+        if (try_adjtime(&tv1, NULL))
+          continue;
+
+        xusleep(1 << i);
+        if (try_adjtime(&tv3, &tv2))
+          continue;
+
+        diff = diff_tv(&tv1, &tv2);
+        if (!has_min || min > diff) {
+          min = diff;
+          has_min = 1;
+        }
+      }
+
+      if (!has_min)
+        continue;
+
+      printf(" %5d (%d)", min, 1 << j);
+      fflush(stdout);
+    }
+    printf("\n");
+  }
+}
+
+int
+main()
+{
+  test_range();
+  test_readonly();
+  test_readwrite();
+  test_slew();
+
+  reset_adjtime();
+
+  return 0;
+}
diff --git a/chrony_3_3/test/kernel/ntpadjtime.c b/chrony_3_3/test/kernel/ntpadjtime.c
new file mode 100644
index 0000000..d6be154
--- /dev/null
+++ b/chrony_3_3/test/kernel/ntpadjtime.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) Miroslav Lichvar  2015
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/* Check the frequency range of the system ntp_adjtime() implementation */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+
+static int
+try_ntpadjtime(struct timex *t)
+{
+  int r;
+  r = ntp_adjtime(t);
+  if (r < 0)
+    printf("ntp_adjtime() failed : %s ", strerror(errno));
+  return r;
+}
+
+static void
+reset_ntpadjtime(void)
+{
+  struct timex t;
+
+  t.modes = MOD_OFFSET | MOD_FREQUENCY;
+  t.offset = 0;
+  t.freq = 0;
+  try_ntpadjtime(&t);
+}
+
+static void
+test_freqrange(void)
+{
+  struct timex t;
+  int i;
+
+  printf("freq range:\n");
+
+  for (i = 0; i <= 1000; i += 50) {
+    t.modes = MOD_FREQUENCY;
+    t.freq = i << 16;
+    printf("%4d ppm => ", i);
+    if (try_ntpadjtime(&t) < 0)
+      continue;
+
+    printf("%4ld ppm : ", t.freq / (1 << 16));
+    printf("%s\n", t.freq == i << 16 ? "ok" : "fail");
+  }
+}
+
+int
+main()
+{
+  test_freqrange();
+
+  reset_ntpadjtime();
+
+  return 0;
+}
diff --git a/chrony_3_3/test/simulation/001-defaults b/chrony_3_3/test/simulation/001-defaults
new file mode 100755
index 0000000..541cdad
--- /dev/null
+++ b/chrony_3_3/test/simulation/001-defaults
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "default test settings"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/002-largenetwork b/chrony_3_3/test/simulation/002-largenetwork
new file mode 100755
index 0000000..fd41106
--- /dev/null
+++ b/chrony_3_3/test/simulation/002-largenetwork
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "large network"
+
+time_rms_limit=5e-4
+
+server_strata=3
+servers=4
+clients=5
+
+client_start=2000
+min_sync_time=2100
+max_sync_time=2300
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/003-largefreqoffset b/chrony_3_3/test/simulation/003-largefreqoffset
new file mode 100755
index 0000000..7210662
--- /dev/null
+++ b/chrony_3_3/test/simulation/003-largefreqoffset
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "large frequency offset"
+
+max_sync_time=1000
+
+for freq_offset in -5e-2 -5e-3 5e-3 5e-2; do
+	# Adjust offset so it's close to 0 on first clock update
+	time_offset=$(awk "BEGIN {print -($freq_offset * 130)}")
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/004-largetimeoffset b/chrony_3_3/test/simulation/004-largetimeoffset
new file mode 100755
index 0000000..5d8e2b6
--- /dev/null
+++ b/chrony_3_3/test/simulation/004-largetimeoffset
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "large time offset"
+
+min_sync_time=1300
+max_sync_time=1400
+
+for time_offset in -1e2 1e2; do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/005-externalstep b/chrony_3_3/test/simulation/005-externalstep
new file mode 100755
index 0000000..709c8a8
--- /dev/null
+++ b/chrony_3_3/test/simulation/005-externalstep
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "external time step"
+
+min_sync_time=1500
+max_sync_time=1550
+
+for step in -1e2 1e2; do
+	# Make one step in 150th second
+	client_step="(* $step (equal 0.1 (sum 1.0) 150))"
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+min_sync_time=5120
+max_sync_time=6200
+client_conf="makestep 1 -1"
+
+for step in -1e8 -1e5 1e5 1e8; do
+	# Make one step in 5000th second
+	client_step="(* $step (equal 0.1 (sum 1.0) 5000))"
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+min_sync_time=$default_min_sync_time
+max_sync_time=$default_max_sync_time
+time_max_limit=2e4
+time_rms_limit=8e3
+
+for step in -1e4 1e4; do
+	# Make a step every 500 seconds
+	client_step="(* $step (equal 0.1 (% (sum 1.0) 500) 0))"
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/006-largejitter b/chrony_3_3/test/simulation/006-largejitter
new file mode 100755
index 0000000..f70e63c
--- /dev/null
+++ b/chrony_3_3/test/simulation/006-largejitter
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "large jitter"
+
+time_offset=1e0
+jitter=1e-1
+
+time_max_limit=5e-1
+freq_max_limit=2e-1
+time_rms_limit=1e-1
+freq_rms_limit=5e-3
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/007-largewander b/chrony_3_3/test/simulation/007-largewander
new file mode 100755
index 0000000..5572cbc
--- /dev/null
+++ b/chrony_3_3/test/simulation/007-largewander
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "large wander"
+
+wander=1e-7
+
+time_max_limit=5e-3
+freq_max_limit=5e-3
+time_rms_limit=1e-3
+freq_rms_limit=1e-4
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/008-ntpera b/chrony_3_3/test/simulation/008-ntpera
new file mode 100755
index 0000000..3c63419
--- /dev/null
+++ b/chrony_3_3/test/simulation/008-ntpera
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+. ./test.common
+test_start "NTP eras"
+
+# Assume NTP_ERA_SPLIT is between years 1960 and 1990
+
+# Set date to 500 seconds before NTP second overflows, this should
+# work correctly with both 32-bit and 64-bit time_t
+export CLKNETSIM_START_DATE=$(date -d 'Feb  7 06:19:56 UTC 2036' +'%s')
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+# The following tests need 64-bit time_t
+grep -q 'HAVE_LONG_TIME_T 1' ../../config.h || test_skip
+
+for year in 1990 2090; do
+	export CLKNETSIM_START_DATE=$(date -d "Jan  1 00:00:00 UTC $year" +'%s')
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+for year in 1950 2130; do
+	export CLKNETSIM_START_DATE=$(date -d "Jan  1 00:00:00 UTC $year" +'%s')
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	# This check is expected to fail
+	check_sync && test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/009-sourceselection b/chrony_3_3/test/simulation/009-sourceselection
new file mode 100755
index 0000000..7e60931
--- /dev/null
+++ b/chrony_3_3/test/simulation/009-sourceselection
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "source selection"
+
+# Falsetickers should be detected if their number is less than half of all
+
+base_delay=1e-3
+servers=5
+
+for falsetickers in 1 2; do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+for falsetickers in 3 4; do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_packet_interval || test_fail
+	# These check are expected to fail
+	check_source_selection && test_fail
+	check_sync && test_fail
+done
+
+# Sources with large asymmetric delay should be excluded
+
+servers=3
+falsetickers=0
+base_delay="(+ 1e-3 (equal 0.1 to 2) (equal 0.1 to 3))"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/010-multrecv b/chrony_3_3/test/simulation/010-multrecv
new file mode 100755
index 0000000..8adfab6
--- /dev/null
+++ b/chrony_3_3/test/simulation/010-multrecv
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+. ./test.common
+
+export CLKNETSIM_RECV_MULTIPLY=4
+
+test_start "multiple received packets"
+
+limit=50000
+client_server_options="minpoll 6 maxpoll 6"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/011-asymjitter b/chrony_3_3/test/simulation/011-asymjitter
new file mode 100755
index 0000000..18e6ec1
--- /dev/null
+++ b/chrony_3_3/test/simulation/011-asymjitter
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "asymmetric jitter"
+
+jitter=5e-4
+jitter_asymmetry=0.47
+limit=100000
+max_sync_time=2000
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/101-poll b/chrony_3_3/test/simulation/101-poll
new file mode 100755
index 0000000..f350777
--- /dev/null
+++ b/chrony_3_3/test/simulation/101-poll
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+. ./test.common
+test_start "minpoll/maxpoll options"
+
+wander=0.0
+jitter=1e-6
+
+time_max_limit=1e-5
+freq_max_limit=1e-5
+time_rms_limit=5e-6
+freq_rms_limit=5e-6
+client_conf="makestep 1e-2 1"
+
+for poll in $(seq 2 14); do
+	client_server_options="minpoll $poll maxpoll $poll"
+	limit=$[2**$poll * 10]
+	min_sync_time=$[2**$poll * 2]
+	max_sync_time=$[2**$poll * 21 / 10 + 1]
+
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/102-iburst b/chrony_3_3/test/simulation/102-iburst
new file mode 100755
index 0000000..bd82530
--- /dev/null
+++ b/chrony_3_3/test/simulation/102-iburst
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+. ./test.common
+test_start "iburst option"
+
+freq_offset=1e-4
+
+client_conf="makestep 1e-2 1
+driftfile tmp/drift"
+client_server_options="iburst"
+
+min_sync_time=4
+max_sync_time=6
+
+echo "100 1.0" > tmp/drift
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/103-initstepslew b/chrony_3_3/test/simulation/103-initstepslew
new file mode 100755
index 0000000..303020e
--- /dev/null
+++ b/chrony_3_3/test/simulation/103-initstepslew
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+. ./test.common
+test_start "initstepslew directive"
+
+freq_offset=0.0
+wander=0.0
+time_rms_limit=1e-3
+limit=100
+
+client_conf="initstepslew 5 192.168.123.1"
+
+min_sync_time=6
+max_sync_time=35
+
+for time_offset in -2.0 -0.2 0.2 2.0; do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+min_sync_time=5
+max_sync_time=5
+
+for time_offset in -1e8 -1e2 1e2 1e8; do
+	run_test || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/104-driftfile b/chrony_3_3/test/simulation/104-driftfile
new file mode 100755
index 0000000..703dad7
--- /dev/null
+++ b/chrony_3_3/test/simulation/104-driftfile
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+. ./test.common
+test_start "driftfile directive"
+
+servers=0
+time_offset=0.0
+wander=0.0
+limit=10
+freq_max_limit=1e-9
+min_sync_time=1
+max_sync_time=1
+client_conf="driftfile tmp/drift"
+
+for freq_offset in -5e-2 -5e-4 -5e-6 5e-6 5e-4 5e-2; do
+	awk "BEGIN {printf \"%.9e 1\", 1e6 - 1 / (1 + $freq_offset) * 1e6}" > tmp/drift
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/105-ntpauth b/chrony_3_3/test/simulation/105-ntpauth
new file mode 100755
index 0000000..4c77f10
--- /dev/null
+++ b/chrony_3_3/test/simulation/105-ntpauth
@@ -0,0 +1,87 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "NTP authentication"
+
+server_conf="keyfile tmp/server.keys"
+client_conf="keyfile tmp/client.keys"
+
+cat > tmp/server.keys <<-EOF
+1 MD5 HEX:6B5D3C6A2E4A74775E4F6F3B7A35453E6E5C5F302D783D2979505C663C295A5E
+2 MD5 HEX:6B5D3C6A2E4A74775E4F6F3B7A35453E6E5C5F302D783D2979505C663C295A5E
+3 MD5 HEX:6B5D3C6A2E4A74775E4F6F3B7A35453E6E5C5F302D783D2979505C663C295A5E
+4 MD5 HEX:6B5D3C6A2E4A74775E4F6F3B7A35453E6E5C5F302D783D2979505C663C295A5E
+EOF
+
+cat > tmp/client.keys <<-EOF
+1 k]<j.Jtw^Oo;z5E>n\_0-x=)yP\f<)Z^
+2 ASCII:k]<j.Jtw^Oo;z5E>n\_0-x=)yP\f<)Z^
+3 MD5 ASCII:k]<j.Jtw^Oo;z5E>n\_0-x=)yP\f<)Z^
+4 MD5 HEX:6B5D3C6A2E4A74775E4F6F3B7A35453E6E5C5F302D783D2979505C663C295A5E
+EOF
+
+keys=4
+
+if grep -q 'FEAT_SECHASH 1' ../../config.h; then
+	hashes="MD5 SHA1 SHA256 SHA384 SHA512"
+else
+	hashes="MD5"
+fi
+
+for hash in $hashes; do
+	keys=$[$keys + 1]
+	key=$(echo $keys $hash HEX:$(tr -c -d '0-9A-F' < /dev/urandom 2> /dev/null | \
+		head -c $[$RANDOM % 64 * 2 + 2]))
+	echo "$key" >> tmp/server.keys
+	echo "$key" >> tmp/client.keys
+done
+
+for version in 3 4; do
+	for key in $(seq $keys); do
+		client_server_options="version $version key $key"
+		run_test || test_fail
+		check_chronyd_exit || test_fail
+		check_source_selection || test_fail
+		check_packet_interval || test_fail
+		check_sync || test_fail
+	done
+done
+
+server_conf=""
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+# This check must fail as the server doesn't know the key
+check_sync && test_fail
+check_packet_interval || test_fail
+
+server_conf="keyfile tmp/server.keys"
+client_conf=""
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+# This check must fail as the client doesn't know the key
+check_sync && test_fail
+check_packet_interval || test_fail
+
+client_conf="keyfile tmp/client.keys"
+clients=2
+peers=2
+max_sync_time=500
+base_delay="$default_base_delay (* -1 (equal 0.1 from 3) (equal 0.1 to 1))"
+client_lpeer_options="key 1"
+client_rpeer_options="key 1"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_sync || test_fail
+
+client_rpeer_options="key 2"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+# This check must fail as the peers are using different keys"
+check_sync && test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/106-refclock b/chrony_3_3/test/simulation/106-refclock
new file mode 100755
index 0000000..c22cd42
--- /dev/null
+++ b/chrony_3_3/test/simulation/106-refclock
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+. ./test.common
+test_start "SHM refclock"
+
+servers=0
+limit=1000
+refclock_jitter=$jitter
+min_sync_time=45
+max_sync_time=70
+chronyc_start=70
+client_conf="refclock SHM 0 stratum 3 delay 1e-3 refid GPS"
+chronyc_conf="tracking"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+check_chronyc_output "^Reference ID.*47505300 \(GPS\)
+Stratum.*: 4
+.*
+Root delay      : 0.001000000 seconds
+.*
+Update interval : 16\.. seconds
+.*$" || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/107-allowdeny b/chrony_3_3/test/simulation/107-allowdeny
new file mode 100755
index 0000000..b11db32
--- /dev/null
+++ b/chrony_3_3/test/simulation/107-allowdeny
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "allow/deny directives"
+
+limit=500
+
+# Note that start_client in clknetsim.bash always adds allow to the config
+
+for server_conf in \
+	"deny" \
+	"deny all" \
+	"deny 192.168.0.0/16" \
+	"deny 192.168.123" \
+	"deny 192.168.123.2" \
+	"deny all
+allow 192.168.124.0/24"
+do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_packet_interval || test_fail
+	# These checks are expected to fail
+	check_source_selection && test_fail
+	check_sync && test_fail
+done
+
+for server_conf in \
+	"deny all
+allow" \
+	"deny all
+allow all" \
+	"deny all
+allow 192.168.123" \
+	"deny all
+allow 192.168.123/24" \
+	"deny 192.168.124.0/24"
+do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/108-peer b/chrony_3_3/test/simulation/108-peer
new file mode 100755
index 0000000..0679f6e
--- /dev/null
+++ b/chrony_3_3/test/simulation/108-peer
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "NTP peers"
+
+# Allow and drop packets to the server in 1000 second intervals, so only one
+# client has access to it and the other is forced to switch to the peer.
+base_delay=$(cat <<-EOF | tr -d '\n'
+  (+ 1e-4
+     (* -1
+        (equal 0.1 from 2)
+        (equal 0.1 to 1)
+        (equal 0.1 (min (% time 2000) 1000) 1000))
+     (* -1
+        (equal 0.1 from 3)
+        (equal 0.1 to 1)
+	(equal 0.1 (max (% time 2000) 1000) 1000)))
+EOF
+)
+
+clients=2
+peers=2
+max_sync_time=1000
+client_server_options="minpoll 6 maxpoll 6"
+client_peer_options="minpoll 6 maxpoll 6"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/109-makestep b/chrony_3_3/test/simulation/109-makestep
new file mode 100755
index 0000000..f984f72
--- /dev/null
+++ b/chrony_3_3/test/simulation/109-makestep
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+. ./test.common
+test_start "makestep directive"
+
+client_conf="makestep 0 -1
+corrtimeratio 1e10"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+limit=200
+jitter=1e-5
+client_conf="makestep 2 1"
+
+min_sync_time=130
+max_sync_time=150
+
+for time_offset in -1.0 -0.1 0.1 1.0; do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+min_sync_time=120
+max_sync_time=140
+
+for time_offset in -1e8 -1e2 1e2 1e8; do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/110-chronyc b/chrony_3_3/test/simulation/110-chronyc
new file mode 100755
index 0000000..d56e724
--- /dev/null
+++ b/chrony_3_3/test/simulation/110-chronyc
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "chronyc"
+
+refclock_jitter=$jitter
+client_conf="
+refclock SHM 0 noselect
+smoothtime 400 0.001 leaponly"
+
+chronyc_conf="activity
+tracking
+sources
+sourcestats
+manual list
+smoothing
+waitsync
+rtcdata"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+
+check_chronyc_output "^200 OK
+1 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+Reference ID    : C0A87B01 \(192\.168\.123\.1\)
+Stratum         : 2
+Ref time \(UTC\)  : Fri Jan 01 00:1.:.. 2010
+System time     : 0\.0000..... seconds (slow|fast) of NTP time
+Last offset     : [+-]0\.000...... seconds
+RMS offset      : 0\.000...... seconds
+Frequency       : (99|100)\.... ppm fast
+Residual freq   : [+-][0-9]\.... ppm
+Skew            : [0-9]\.... ppm
+Root delay      : 0\.000...... seconds
+Root dispersion : 0\.000...... seconds
+Update interval : [0-9]+\.. seconds
+Leap status     : Normal
+210 Number of sources = 2
+MS Name/IP address         Stratum Poll Reach LastRx Last sample               
+===============================================================================
+#\? SHM0                          0   4   377    [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
+\^\* 192\.168\.123\.1                 1   [67]   377    [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
+210 Number of sources = 2
+Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev
+==============================================================================
+SHM0                       [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\....  [0-9 +-]+[un]s [0-9 ]+[un]s
+192\.168\.123\.1              [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\....  [0-9 +-]+[un]s [0-9 ]+[un]s
+210 n_samples = 0
+#    Date     Time\(UTC\)    Slewed   Original   Residual
+=======================================================
+Active         : Yes \(leap second only\)
+Offset         : \+0\.000000000 seconds
+Frequency      : \+0\.000000 ppm
+Wander         : \+0\.000000 ppm per second
+Last update    : [0-9]+\.. seconds ago
+Remaining time : 0\.0 seconds
+try: 1, refid: C0A87B01, correction: 0\.000......, skew: .\....
+513 RTC driver not running$" \
+|| test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/111-knownclient b/chrony_3_3/test/simulation/111-knownclient
new file mode 100755
index 0000000..3d3fd87
--- /dev/null
+++ b/chrony_3_3/test/simulation/111-knownclient
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "reply to client configured as server"
+
+server_conf="server 192.168.123.2 noselect
+acquisitionport 123"
+client_conf="acquisitionport 123"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_port || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/112-port b/chrony_3_3/test/simulation/112-port
new file mode 100755
index 0000000..e983757
--- /dev/null
+++ b/chrony_3_3/test/simulation/112-port
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "port and acquisitionport directives"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+# This check is expected to fail
+check_packet_port && test_fail
+
+client_conf="acquisitionport 123"
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_packet_port || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+client_conf=""
+for server_conf in \
+	"port 0" \
+	"acquisitionport 123
+port 0"
+do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_packet_port || test_fail
+	check_packet_interval || test_fail
+	# These checks are expected to fail
+	check_source_selection && test_fail
+	check_sync && test_fail
+done
+
+server_conf="port 124
+acquisitionport 123"
+client_server_options="port 124"
+for client_conf in \
+	"acquisitionport 0" \
+	"acquisitionport 123" \
+	"acquisitionport 124"
+do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+	# This check is expected to fail
+	check_packet_port && test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/113-leapsecond b/chrony_3_3/test/simulation/113-leapsecond
new file mode 100755
index 0000000..5b9758f
--- /dev/null
+++ b/chrony_3_3/test/simulation/113-leapsecond
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+. ./test.common
+test_start "leap second"
+
+export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Dec 30 2008 0:00:00' +'%s')
+
+leap=$[2 * 24 * 3600]
+limit=$[4 * 24 * 3600]
+client_start=$[2 * 3600]
+server_conf="refclock SHM 0 dpoll 10 poll 10
+leapsectz right/UTC"
+refclock_jitter=1e-9
+refclock_offset="(* -1.0 (equal 0.1 (max (sum 1.0) $leap) $leap))"
+
+for leapmode in system step slew; do
+	client_conf="leapsecmode $leapmode"
+	if [ $leapmode = slew ]; then
+		max_sync_time=$[$leap + 12]
+	else
+		max_sync_time=$[$leap]
+	fi
+
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+client_server_options="trust"
+client_conf="refclock SHM 0 dpoll 10 poll 10 delay 1e-3"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+client_server_options=""
+client_conf="leapsecmode system"
+min_sync_time=230000
+max_sync_time=240000
+
+for smoothmode in "" "leaponly"; do
+	server_conf="refclock SHM 0 dpoll 10 poll 10
+	leapsectz right/UTC
+	leapsecmode slew
+	smoothtime 400 0.001 $smoothmode"
+
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/114-presend b/chrony_3_3/test/simulation/114-presend
new file mode 100755
index 0000000..3113253
--- /dev/null
+++ b/chrony_3_3/test/simulation/114-presend
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+. ./test.common
+test_start "presend option"
+
+min_sync_time=136
+max_sync_time=260
+client_server_options="presend 6 maxdelay 16"
+client_conf="maxdistance 10"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+base_delay=5
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/115-cmdmontime b/chrony_3_3/test/simulation/115-cmdmontime
new file mode 100755
index 0000000..2806a1f
--- /dev/null
+++ b/chrony_3_3/test/simulation/115-cmdmontime
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "cmdmon timestamps"
+
+# The following tests need 64-bit time_t
+grep -q 'HAVE_LONG_TIME_T 1' ../../config.h || test_skip
+
+limit=2
+client_server_options="noselect"
+client_conf="local stratum 1"
+chronyc_start="1.5"
+chronyc_conf="tracking"
+
+for year in `seq 1850 100 2300`; do
+	date="Jan 01 00:00:00 $year"
+	export CLKNETSIM_START_DATE=$(date -d "$date UTC" +'%s')
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_chronyc_output "^.*Ref time \(UTC\).*$date.*$" || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/116-minsources b/chrony_3_3/test/simulation/116-minsources
new file mode 100755
index 0000000..392f360
--- /dev/null
+++ b/chrony_3_3/test/simulation/116-minsources
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "minsources directive"
+
+client_conf="minsources 3"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_packet_interval || test_fail
+# These check are expected to fail
+check_source_selection && test_fail
+check_sync && test_fail
+
+servers=3
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_packet_interval || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/117-fallbackdrift b/chrony_3_3/test/simulation/117-fallbackdrift
new file mode 100755
index 0000000..22270c9
--- /dev/null
+++ b/chrony_3_3/test/simulation/117-fallbackdrift
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+. ./test.common
+test_start "fallback drift"
+
+limit=100000
+wander=0.0
+jitter=1e-6
+time_offset=10
+freq_offset="(* 1e-4 (sine 1000))"
+base_delay="(* -1.0 (equal 0.1 (min time 4250) 4250))"
+client_server_options="minpoll 4 maxpoll 4"
+client_conf="fallbackdrift 6 10"
+max_sync_time=4500
+time_max_limit=1e0
+time_rms_limit=1e0
+freq_max_limit=2e-4
+freq_rms_limit=1e-4
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/118-maxdelay b/chrony_3_3/test/simulation/118-maxdelay
new file mode 100755
index 0000000..22b9a50
--- /dev/null
+++ b/chrony_3_3/test/simulation/118-maxdelay
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+. ./test.common
+test_start "maxdelay options"
+
+max_sync_time=2000
+base_delay=1e-5
+jitter=1e-5
+wander=0.0
+freq_offset="(sum 1e-10)"
+time_rms_limit=2e-4
+
+client_server_options="maxpoll 6 maxdelay 3e-5 maxdelayratio 2.0 maxdelaydevratio 2.0"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+for client_server_options in "maxpoll 6 maxdelay 2e-5"; do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_packet_interval || test_fail
+	check_sync && test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/119-smoothtime b/chrony_3_3/test/simulation/119-smoothtime
new file mode 100755
index 0000000..6b4ae39
--- /dev/null
+++ b/chrony_3_3/test/simulation/119-smoothtime
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+. ./test.common
+test_start "smoothtime option"
+
+server_strata=2
+server_conf="smoothtime 400 0.001"
+server_server_options="minpoll 8"
+min_sync_time=600
+max_sync_time=800
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+limit=10000
+refclock_jitter=1e-4
+refclock_offset="(* 10.0 (equal 0.1 (max (sum 1.0) 1000) 1000))"
+server_step="(* -10.0 (equal 0.1 (sum 1.0) 1))"
+server_strata=1
+server_conf="refclock SHM 0 dpoll 4 poll 6
+smoothtime 2000 1
+maxjitter 10.0"
+time_offset=-10
+server_server_options=""
+client_server_options="minpoll 6 maxpoll 6"
+client_conf="corrtimeratio 100"
+min_sync_time=8000
+max_sync_time=9000
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+client_server_options="minpoll 6 maxpoll 6 xleave maxdelay 1e-1"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+client_server_options="minpoll 6 maxpoll 6"
+min_sync_time=$default_min_sync_time
+max_sync_time=$default_max_sync_time
+time_max_limit=11
+time_rms_limit=11
+freq_max_limit=1e-2
+freq_rms_limit=2e-3
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+refclock_jitter=1e-9
+refclock_offset="(* 1e-1 (triangle 1000) (+ -1.0 (pulse 1000 10000)))"
+server_step=""
+server_conf="refclock SHM 0 dpoll 4 poll 6 minsamples 4 maxsamples 4
+smoothtime 1e4 1e-6"
+client_server_options="minpoll 4 maxpoll 4"
+time_offset=0.1
+jitter=1e-6
+wander=0.0
+min_sync_time=30
+max_sync_time=40
+time_max_limit=1e-5
+time_rms_limit=5e-6
+freq_max_limit=1e-6
+freq_rms_limit=1e-7
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/120-selectoptions b/chrony_3_3/test/simulation/120-selectoptions
new file mode 100755
index 0000000..7e10293
--- /dev/null
+++ b/chrony_3_3/test/simulation/120-selectoptions
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "source selection options"
+
+servers=3
+falsetickers=2
+
+base_delay=0.6
+client_server_conf="
+server 192.168.123.1
+server 192.168.123.2
+server 192.168.123.3 trust"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+client_server_conf="
+server 192.168.123.1
+server 192.168.123.2
+server 192.168.123.3 prefer"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+# This check is expected to fail
+check_sync && test_fail
+
+base_delay=1.1
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+base_delay=$default_base_delay
+falsetickers=1
+
+client_server_conf="
+server 192.168.123.1
+server 192.168.123.2
+server 192.168.123.3 require"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+client_server_conf="
+server 192.168.123.1 require
+server 192.168.123.2
+server 192.168.123.3"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_packet_interval || test_fail
+# These checks are expected to fail
+check_source_selection && test_fail
+check_sync && test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/121-orphan b/chrony_3_3/test/simulation/121-orphan
new file mode 100755
index 0000000..ed92153
--- /dev/null
+++ b/chrony_3_3/test/simulation/121-orphan
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "orphan option"
+
+server_strata=3
+server_conf="local stratum 5 orphan
+server 192.168.123.1
+server 192.168.123.2
+server 192.168.123.3"
+max_sync_time=500
+chronyc_start=300
+chronyc_conf="tracking"
+time_rms_limit=5e-4
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+check_chronyc_output "^.*Stratum *: 7.*$" || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/122-xleave b/chrony_3_3/test/simulation/122-xleave
new file mode 100755
index 0000000..93f767e
--- /dev/null
+++ b/chrony_3_3/test/simulation/122-xleave
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+. ./test.common
+test_start "interleaved mode"
+
+client_server_options="xleave"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+clients=2
+peers=2
+max_sync_time=500
+base_delay="(+ 1e-4 (* -1 (equal 0.1 from 2) (equal 0.1 to 1)))"
+
+client_lpeer_options="xleave minpoll 5 maxpoll 5"
+client_rpeer_options="minpoll 5 maxpoll 5"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+# These checks are expected to fail
+check_source_selection && test_fail
+check_sync && test_fail
+
+for rpoll in 4 5 6; do
+	client_rpeer_options="xleave minpoll $rpoll maxpoll $rpoll"
+
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_sync || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/123-mindelay b/chrony_3_3/test/simulation/123-mindelay
new file mode 100755
index 0000000..cde214a
--- /dev/null
+++ b/chrony_3_3/test/simulation/123-mindelay
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "mindelay and asymmetry options"
+
+jitter_asymmetry=0.499
+time_rms_limit=1e-6
+time_freq_limit=1e-9
+wander=1e-12
+
+for client_server_options in "mindelay 2e-4 asymmetry 0.499"; do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_packet_interval || test_fail
+	check_sync || test_fail
+done
+
+for client_server_options in "mindelay 1e-4 asymmetry 0.499" "mindelay 2e-4 asymmetry 0.0"; do
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_source_selection || test_fail
+	check_sync && test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/124-tai b/chrony_3_3/test/simulation/124-tai
new file mode 100755
index 0000000..b5be030
--- /dev/null
+++ b/chrony_3_3/test/simulation/124-tai
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+. ./test.common
+test_start "tai option"
+
+export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Dec 31 2008 23:50:00' +'%s')
+
+leap=$[10 * 60]
+limit=$[20 * 60]
+min_sync_time=2
+max_sync_time=15
+refclock_jitter=1e-6
+servers=0
+
+refclock_offset="(+ -34 (equal 0.1 (max (sum 1.0) $leap) $leap))"
+client_conf="
+refclock SHM 0 dpoll 0 poll 0 tai
+leapsectz right/UTC
+leapsecmode ignore
+maxchange 1e-3 1 0"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Jan 01 2009 00:10:00' +'%s')
+
+time_offset=-1000
+refclock_offset="(+ -34)"
+client_conf="
+refclock SHM 0 dpoll 0 poll 0 tai
+leapsectz right/UTC
+makestep 1 1
+maxchange 1e-3 1 0"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/125-packetloss b/chrony_3_3/test/simulation/125-packetloss
new file mode 100755
index 0000000..95604da
--- /dev/null
+++ b/chrony_3_3/test/simulation/125-packetloss
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "packet loss"
+
+# Drop 33% of packets by default and 100% on the 3->1 path
+base_delay=$(cat <<-EOF | tr -d '\n'
+  (+ 1e-4
+     (* -1 (equal 0.33 (uniform) 1.0))
+     (* -1 (equal 0.1 from 3) (equal 0.1 to 1)))
+EOF
+)
+clients=2
+peers=2
+jitter=1e-5
+limit=20000
+max_sync_time=10000
+
+for options in "maxpoll 8" "maxpoll 8 xleave"; do
+	client_server_options=$options
+	client_peer_options=$options
+
+	run_test || test_fail
+	check_chronyd_exit || test_fail
+	check_sync || test_fail
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/126-burst b/chrony_3_3/test/simulation/126-burst
new file mode 100755
index 0000000..d63f290
--- /dev/null
+++ b/chrony_3_3/test/simulation/126-burst
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+. ./test.common
+
+test_start "burst option"
+
+# Pass every fourth packet on the 2->1 path
+base_delay=$(cat <<-EOF | tr -d '\n'
+  (+ 1e-4
+     (* -1
+        (equal 0.1 from 2)
+        (equal 0.1 to 1)
+        (equal 0.1 (min (% (sum 1) 4) 1) 1)))
+EOF
+)
+
+client_server_options="burst polltarget 1"
+min_sync_time=700
+max_sync_time=730
+client_max_min_out_interval=2.2
+client_min_mean_out_interval=150.0
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+# Add a significant delay to 70% of packets on the 2->1 path after 6th packet
+base_delay=$(cat <<-EOF | tr -d '\n'
+  (+ 1e-4
+     (* 0.15
+        (equal 0.1 from 2)
+        (equal 0.1 to 1)
+        (equal 0.1 (min (sum 1) 7) 7)
+        (equal 0.7 (uniform) 0.0)))
+EOF
+)
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/201-freqaccumulation b/chrony_3_3/test/simulation/201-freqaccumulation
new file mode 100755
index 0000000..7a9c22c
--- /dev/null
+++ b/chrony_3_3/test/simulation/201-freqaccumulation
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+. ./test.common
+
+# Test fix in commit 60d0fa299307076143da94d36deb7b908fa9bdb7
+
+test_start "frequency accumulation"
+
+time_offset=100.0
+jitter=1e-6
+base_delay=1e-6
+wander=0.0
+
+limit=180
+time_max_limit=1e-5
+freq_max_limit=1e-7
+time_rms_limit=1e-5
+freq_rms_limit=1e-7
+min_sync_time=120
+max_sync_time=140
+
+client_server_options="minpoll 6 maxpoll 6"
+client_conf="driftfile tmp/drift
+makestep 1 1"
+
+for freq_offset in -5e-2 -5e-4 5e-4 5e-2; do
+	for drift in -1e+4 -1e+2 1e+2 1e+4; do
+		echo "$drift 100000" > tmp/drift
+		run_test || test_fail
+		check_chronyd_exit || test_fail
+		check_sync || test_fail
+	done
+done
+
+test_pass
diff --git a/chrony_3_3/test/simulation/202-prefer b/chrony_3_3/test/simulation/202-prefer
new file mode 100755
index 0000000..ae24848
--- /dev/null
+++ b/chrony_3_3/test/simulation/202-prefer
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+. ./test.common
+
+# Test fix in commit 4253075a97141edfa62043ab71bd0673587e6629
+
+test_start "prefer option"
+
+servers=3
+client_server_conf="
+server 192.168.123.1
+server 192.168.123.2
+server 192.168.123.3 prefer"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+test_pass
diff --git a/chrony_3_3/test/simulation/README b/chrony_3_3/test/simulation/README
new file mode 100644
index 0000000..e174500
--- /dev/null
+++ b/chrony_3_3/test/simulation/README
@@ -0,0 +1,11 @@
+This is a collection of simulation tests using the clknetsim simulator
+(supported on Linux only).
+
+https://github.com/mlichvar/clknetsim
+
+The CLKNETSIM_PATH environment variable should point to the directory where
+clknetsim was downloaded and compiled. If the variable is not set, the tests
+will look for clknetsim in ./clknetsim in the current directory.
+
+The tests are written in bash and they can be run directly. The ./run script
+runs all tests.
diff --git a/chrony_3_3/test/simulation/run b/chrony_3_3/test/simulation/run
new file mode 100755
index 0000000..463e8dd
--- /dev/null
+++ b/chrony_3_3/test/simulation/run
@@ -0,0 +1,90 @@
+#!/bin/bash
+
+print_help() {
+	echo "$1 [-a] [-i ITERATIONS] [-m MAXFAILS] [-s SEED] [TEST]..."
+}
+
+run_test() {
+	local result name=$1 seed=$2
+
+	CLKNETSIM_RANDOM_SEED=$seed ./$name
+	result=$?
+
+	if [ $result -ne 0 -a $result -ne 9 ]; then
+		if [ $abort_on_fail -ne 0 ]; then
+			echo 1>&2
+			echo Failed with random seed $seed 1>&2
+			exit 1
+		fi
+		failed_seeds=(${failed_seeds[@]} $seed)
+	fi
+
+	return $result
+}
+
+abort_on_fail=0
+iterations=1
+max_fails=0
+random_seed=${CLKNETSIM_RANDOM_SEED:-$RANDOM}
+
+while getopts ":ai:m:s:" opt; do
+	case $opt in
+		a) abort_on_fail=1;;
+		i) iterations=$OPTARG;;
+		m) max_fails=$OPTARG;;
+		s) random_seed=$OPTARG;;
+		*) print_help "$0"; exit 3;;
+	esac
+done
+
+shift $[$OPTIND - 1]
+
+passed=() failed=() skipped=() failed_seeds=()
+
+[ $# -gt 0 ] && tests=($@) || tests=([0-9]*-*[^_])
+
+for test in "${tests[@]}"; do
+	if [ $iterations -gt 1 ]; then
+		printf "%-30s" "$test"
+		fails=0
+		for i in $(seq 1 $iterations); do
+			run_test $test $[$random_seed + $i - 1] > /dev/null
+			case $? in
+				0) echo -n ".";;
+				9) break;;
+				*) echo -n "x"; fails=$[$fails + 1];;
+			esac
+		done
+		if [ $i -lt $iterations ]; then
+			printf "%${iterations}s" ""
+			echo " SKIP"
+			result=9
+		elif [ $fails -gt $max_fails ]; then
+			echo " FAIL"
+			result=1
+		else
+			echo " PASS"
+			result=0
+		fi
+	else
+		printf "%s   " "$test"
+		run_test $test $random_seed
+		result=$?
+		echo
+	fi
+
+	case $result in
+		0) passed=(${passed[@]} $test);;
+		9) skipped=(${skipped[@]} $test);;
+		*) failed=(${failed[@]} $test);;
+	esac
+done
+
+echo
+echo "SUMMARY:"
+echo "  TOTAL  $[${#passed[@]} + ${#failed[@]} + ${#skipped[@]}]"
+echo "  PASSED ${#passed[@]}"
+echo "  FAILED ${#failed[@]}    (${failed[@]}) (${failed_seeds[@]})"
+echo "  SKIPPED ${#skipped[@]}   (${skipped[@]})"
+
+[ ${#failed[@]} -eq 0 ]
diff --git a/chrony_3_3/test/simulation/test.common b/chrony_3_3/test/simulation/test.common
new file mode 100644
index 0000000..0cd0fce
--- /dev/null
+++ b/chrony_3_3/test/simulation/test.common
@@ -0,0 +1,455 @@
+# Copyright (C) 2013-2014  Miroslav Lichvar <mlichvar@redhat.com>
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+export LC_ALL=C
+export PATH=../../:$PATH
+export CLKNETSIM_PATH=${CLKNETSIM_PATH:-clknetsim}
+
+if [ ! -x $CLKNETSIM_PATH/clknetsim ]; then
+	echo "SKIP (clknetsim not found)"
+	exit 9
+fi
+
+. $CLKNETSIM_PATH/clknetsim.bash
+
+# Default test testings
+
+default_limit=10000
+default_time_offset=1e-1
+default_freq_offset=1e-4
+default_base_delay=1e-4
+default_jitter=1e-4
+default_jitter_asymmetry=0.0
+default_wander=1e-9
+default_refclock_jitter=""
+default_refclock_offset=0.0
+
+default_update_interval=0
+default_shift_pll=2
+
+default_server_strata=1
+default_servers=1
+default_clients=1
+default_peers=0
+default_falsetickers=0
+default_server_start=0.0
+default_client_start=0.0
+default_chronyc_start=1000.0
+default_server_step=""
+default_client_step=""
+
+default_client_server_conf=""
+default_server_server_options=""
+default_client_server_options=""
+default_server_peer_options=""
+default_server_lpeer_options=""
+default_server_rpeer_options=""
+default_client_peer_options=""
+default_client_lpeer_options=""
+default_client_rpeer_options=""
+default_server_conf=""
+default_client_conf=""
+default_chronyc_conf=""
+default_chronyd_options=""
+
+default_time_max_limit=1e-3
+default_freq_max_limit=5e-4
+default_time_rms_limit=3e-4
+default_freq_rms_limit=1e-5
+default_min_sync_time=120
+default_max_sync_time=210
+
+default_client_min_mean_out_interval=0.0
+default_client_max_min_out_interval=inf
+
+# Initialize test settings from their defaults
+for defopt in $(declare | grep '^default_'); do
+	defoptname=${defopt%%=*}
+	optname=${defoptname#default_}
+	eval "[ -z \"\${$optname:+a}\" ] && $optname=\"\$$defoptname\""
+done
+
+test_start() {
+	rm -f tmp/*
+	echo "Testing $@:"
+}
+
+test_pass() {
+	echo "PASS"
+	exit 0
+}
+
+test_fail() {
+	echo "FAIL"
+	exit 1
+}
+
+test_skip() {
+	echo "SKIP"
+	exit 9
+}
+
+test_ok() {
+	pad_line
+	echo -e "\tOK"
+	return 0
+}
+
+test_bad() {
+	pad_line
+	echo -e "\tBAD"
+	return 1
+}
+
+test_error() {
+	pad_line
+	echo -e "\tERROR"
+	return 1
+}
+
+msg_length=0
+pad_line() {
+	local line_length=56
+	[ $msg_length -lt $line_length ] && \
+		printf "%$[$line_length - $msg_length]s" ""
+	msg_length=0
+}
+
+# Print aligned message
+test_message() {
+	local level=$1 eol=$2
+	shift 2
+	local msg="$*"
+
+	while [ $level -gt 0 ]; do
+		echo -n "  "
+		level=$[$level - 1]
+		msg_length=$[$msg_length + 2]
+	done
+	echo -n "$msg"
+
+	msg_length=$[$msg_length + ${#msg}]
+	if [ $eol -ne 0 ]; then
+		echo
+		msg_length=0
+	fi
+}
+
+get_wander_expr() {
+	local scaled_wander
+
+	scaled_wander=$(awk "BEGIN {print $wander / \
+		sqrt($update_interval < 0 ? 2^-($update_interval) : 1)}")
+
+	echo "(+ $freq_offset (sum (* $scaled_wander (normal))))"
+}
+
+
+get_delay_expr() {
+	local direction=$1 asym
+
+	if [ $jitter_asymmetry == "0.0" ]; then
+		asym=""
+	elif [ $direction = "up" ]; then
+		asym=$(awk "BEGIN {print 1 - 2 * $jitter_asymmetry}")
+	elif [ $direction = "down" ]; then
+		asym=$(awk "BEGIN {print 1 + 2 * $jitter_asymmetry}")
+	fi
+	echo "(+ $base_delay (* $asym $jitter (exponential)))"
+}
+
+get_refclock_expr() {
+	echo "(+ $refclock_offset (* $refclock_jitter (normal)))"
+}
+
+get_chronyd_nodes() {
+	echo $[$servers * $server_strata + $clients]
+}
+
+get_chronyd_conf() {
+	local i stratum=$1 peer=$2
+
+	if [ $stratum -eq 1 ]; then
+		echo "local stratum 1"
+		echo "$server_conf"
+	elif [ $stratum -le $server_strata ]; then
+		for i in $(seq 1 $servers); do
+			echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $server_server_options"
+		done
+		for i in $(seq 1 $peers); do
+			[ $i -eq $peer -o $i -gt $servers ] && continue
+			echo -n "peer 192.168.123.$[$servers * ($stratum - 1) + $i] $server_peer_options "
+			[ $i -lt $peer ] && echo "$server_lpeer_options" || echo "$server_rpeer_options"
+		done
+		echo "$server_conf"
+	else
+		if [ -n "$client_server_conf" ]; then
+			echo "$client_server_conf"
+		else
+			for i in $(seq 1 $servers); do
+				echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $client_server_options"
+			done
+		fi
+		for i in $(seq 1 $peers); do
+			[ $i -eq $peer -o $i -gt $clients ] && continue
+			echo -n "peer 192.168.123.$[$servers * ($stratum - 1) + $i] $client_peer_options "
+			[ $i -lt $peer ] && echo "$client_lpeer_options" || echo "$client_rpeer_options"
+		done
+		echo "$client_conf"
+	fi
+}
+
+# Check if the clock was well synchronized
+check_sync() {
+	local i sync_time max_time_error max_freq_error ret=0
+	local rms_time_error rms_freq_error
+
+	test_message 2 1 "checking clock sync time, max/rms time/freq error:"
+
+	for i in $(seq 1 $(get_chronyd_nodes)); do
+		[ $i -gt $[$servers * $server_strata] ] || continue
+
+		sync_time=$(find_sync tmp/log.offset tmp/log.freq $i \
+			$time_max_limit $freq_max_limit 1.0)
+		max_time_error=$(get_stat 'Maximum absolute offset' $i)
+		max_freq_error=$(get_stat 'Maximum absolute frequency' $i)
+		rms_time_error=$(get_stat 'RMS offset' $i)
+		rms_freq_error=$(get_stat 'RMS frequency' $i)
+
+		test_message 3 0 "node $i: $sync_time $(printf '%.2e %.2e %.2e %.2e' \
+			$max_time_error $max_freq_error $rms_time_error $rms_freq_error)"
+
+		check_stat $sync_time $min_sync_time $max_sync_time && \
+			check_stat $max_time_error 0.0 $time_max_limit && \
+			check_stat $max_freq_error 0.0 $freq_max_limit && \
+			check_stat $rms_time_error 0.0 $time_rms_limit && \
+			check_stat $rms_freq_error 0.0 $freq_rms_limit && \
+			test_ok || test_bad
+
+		[ $? -eq 0 ] || ret=1
+	done
+
+	return $ret
+}
+
+# Check if chronyd exited properly
+check_chronyd_exit() {
+	local i ret=0
+
+	test_message 2 1 "checking chronyd exit:"
+
+	for i in $(seq 1 $(get_chronyd_nodes)); do
+		test_message 3 0 "node $i:"
+
+		tail -n 1 tmp/log.$i | grep -q 'chronyd exiting' && \
+			! grep -q 'Adjustment.*exceeds.*exiting' tmp/log.$i && \
+			test_ok || test_bad
+		[ $? -eq 0 ] || ret=1
+	done
+
+	return $ret
+}
+
+# Check for problems in source selection
+check_source_selection() {
+	local i ret=0
+
+	test_message 2 1 "checking source selection:"
+
+	for i in $(seq $[$servers * $server_strata + 1] $(get_chronyd_nodes)); do
+		test_message 3 0 "node $i:"
+
+		! grep -q 'no majority\|no selectable sources' tmp/log.$i && \
+			grep -q 'Selected source' tmp/log.$i && \
+			test_ok || test_bad
+		[ $? -eq 0 ] || ret=1
+	done
+
+	return $ret
+}
+
+# Check if incoming and outgoing packet intervals are sane
+check_packet_interval() {
+	local i ret=0 mean_in_interval mean_out_interval min_in_interval min_out_interval
+
+	test_message 2 1 "checking mean/min incoming/outgoing packet interval:"
+
+	for i in $(seq 1 $(get_chronyd_nodes)); do
+		mean_in_interval=$(get_stat 'Mean incoming packet interval' $i)
+		mean_out_interval=$(get_stat 'Mean outgoing packet interval' $i)
+		min_in_interval=$(get_stat 'Minimum incoming packet interval' $i)
+		min_out_interval=$(get_stat 'Minimum outgoing packet interval' $i)
+
+		test_message 3 0 "node $i: $(printf '%.2e %.2e %.2e %.2e' \
+			$mean_in_interval $mean_out_interval $min_in_interval $min_out_interval)"
+
+		# Check that the mean intervals are non-zero and shorter than
+		# limit, incoming is not longer than outgoing for stratum 1
+		# servers, outgoing is not longer than incoming for clients,
+		# and the minimum outgoing interval is not shorter than the NTP
+		# sampling separation or iburst interval for clients
+		nodes=$[$servers * $server_strata + $clients]
+		check_stat $mean_in_interval 0.1 inf && \
+			check_stat $mean_out_interval 0.1 inf && \
+			([ $i -gt $servers ] || \
+				check_stat $mean_in_interval 0.0 $mean_out_interval 10*$jitter) && \
+			([ $i -le $[$servers * $server_strata] ] || \
+				check_stat $mean_out_interval $client_min_mean_out_interval \
+					$mean_in_interval 10*$jitter) && \
+			([ $i -le $[$servers * $server_strata] ] || \
+				check_stat $min_out_interval \
+					$([ $servers -gt 1 ] && echo 0.18 || echo 1.8) \
+					$client_max_min_out_interval) && \
+			test_ok || test_bad
+
+		[ $? -eq 0 ] || ret=1
+	done
+
+	return $ret
+}
+
+# Compare chronyc output with specified pattern
+check_chronyc_output() {
+	local i ret=0 pattern=$1
+
+	test_message 2 1 "checking chronyc output:"
+
+	for i in $(seq $[$(get_chronyd_nodes) + 1] $[$(get_chronyd_nodes) + $clients]); do
+		test_message 3 0 "node $i:"
+
+		[[ "$(cat tmp/log.$i)" =~ $pattern ]] && \
+			test_ok || test_bad
+		[ $? -eq 0 ] || ret=1
+	done
+
+	return $ret
+}
+
+# Check if only NTP port (123) was used
+check_packet_port() {
+	local i ret=0 port=123
+
+	test_message 2 1 "checking port numbers in packet log:"
+
+	for i in $(seq 1 $(get_chronyd_nodes)); do
+		test_message 3 0 "node $i:"
+
+		grep -E -q "	$port	[0-9]+\$" tmp/log.packets && \
+			! grep -E "^[0-9e.+-]+	$i	" tmp/log.packets | \
+			grep -E -q -v "	$port	[0-9]+\$" && \
+			test_ok || test_bad
+		[ $? -eq 0 ] || ret=1
+	done
+
+	return $ret
+}
+
+# Print test settings which differ from default value
+print_nondefaults() {
+	local defopt defoptname optname
+
+	test_message 2 1 "non-default settings:"
+	declare | grep '^default_*' | while read defopt; do
+		defoptname=${defopt%%=*}
+		optname=${defoptname#default_}
+		eval "[ \"\$$optname\" = \"\$$defoptname\" ]" || \
+			test_message 3 1 $(eval "echo $optname=\$$optname")
+	done
+}
+
+run_simulation() {
+	local nodes=$1
+
+	test_message 2 0 "running simulation:"
+
+	start_server $nodes \
+		-o tmp/log.offset -f tmp/log.freq -p tmp/log.packets \
+		-R $(awk "BEGIN {print $update_interval < 0 ? 2^-($update_interval) : 1}") \
+		-r $(awk "BEGIN {print $max_sync_time * 2^$update_interval}") \
+		-l $(awk "BEGIN {print $limit * 2^$update_interval}") && test_ok || test_error
+}
+
+run_test() {
+	local i j n stratum node nodes step start freq offset conf
+
+	test_message 1 1 "network with $servers*$server_strata servers and $clients clients:"
+	print_nondefaults
+
+	nodes=$(get_chronyd_nodes)
+	[ -n "$chronyc_conf" ] && nodes=$[$nodes + $clients]
+
+	for i in $(seq 1 $nodes); do
+		echo "node${i}_shift_pll = $shift_pll"
+		for j in $(seq 1 $nodes); do
+			[ $i -eq $j ] && continue
+			echo "node${i}_delay${j} = $(get_delay_expr up)"
+			echo "node${j}_delay${i} = $(get_delay_expr down)"
+		done
+	done > tmp/conf
+
+	node=1
+
+	for stratum in $(seq 1 $[$server_strata + 1]); do
+		[ $stratum -le $server_strata ] && n=$servers || n=$clients
+
+		for i in $(seq 1 $n); do
+			test_message 2 0 "starting node $node:"
+			if [ $stratum -eq 1 ]; then
+				step=$server_step
+				start=$server_start
+				freq=""
+				[ $i -le $falsetickers ] && offset=$i.0 || offset=0.0
+			elif [ $stratum -le $server_strata ]; then
+				step=$server_step
+				start=$server_start
+				freq=$(get_wander_expr)
+				offset=0.0
+			else
+				step=$client_step
+				start=$client_start
+				freq=$(get_wander_expr)
+				offset=$time_offset
+			fi
+
+			conf=$(get_chronyd_conf $stratum $i $n)
+
+			[ -z "$freq" ] || echo "node${node}_freq = $freq" >> tmp/conf
+			[ -z "$step" ] || echo "node${node}_step = $step" >> tmp/conf
+			[ -z "$refclock_jitter" ] || \
+				echo "node${node}_refclock = $(get_refclock_expr)" >> tmp/conf
+			echo "node${node}_offset = $offset" >> tmp/conf
+			echo "node${node}_start = $start" >> tmp/conf
+			start_client $node chronyd "$conf" "" "$chronyd_options" && \
+				test_ok || test_error
+
+			[ $? -ne 0 ] && return 1
+			node=$[$node + 1]
+		done
+	done
+
+	for i in $(seq 1 $[$nodes - $node + 1]); do
+		test_message 2 0 "starting node $node:"
+
+		echo "node${node}_start = $chronyc_start" >> tmp/conf
+		start_client $node chronyc "$chronyc_conf" "" \
+			"-n -h 192.168.123.$[$node - $clients]" && \
+			test_ok || test_error
+
+		[ $? -ne 0 ] && return 1
+		node=$[$node + 1]
+	done
+
+	run_simulation $nodes
+}
diff --git a/chrony_3_3/test/unit/Makefile b/chrony_3_3/test/unit/Makefile
new file mode 100644
index 0000000..75f7861
--- /dev/null
+++ b/chrony_3_3/test/unit/Makefile
@@ -0,0 +1,45 @@
+TEST_WRAPPER =
+CHRONY_SRCDIR = ../..
+
+CC = gcc
+CFLAGS = -O2 -g -D_FORTIFY_SOURCE=2 -fPIE -fstack-protector-strong --param=ssp-buffer-size=4 -Wmissing-prototypes -Wall -pthread
+CPPFLAGS = -I$(CHRONY_SRCDIR) 
+LDFLAGS =  -pie -Wl,-z,relro,-z,now -lm 
+
+SHARED_OBJS = test.o
+
+TEST_OBJS := $(sort $(patsubst %.c,%.o,$(wildcard *.c)))
+TESTS := $(patsubst %.o,%.test,$(filter-out $(SHARED_OBJS),$(TEST_OBJS)))
+
+FILTER_OBJS = %/main.o %/client.o %/getdate.o
+CHRONY_OBJS := $(filter-out $(FILTER_OBJS),$(wildcard $(CHRONY_SRCDIR)/*.o))
+
+all: $(TESTS)
+
+%.test: %.o $(SHARED_OBJS)
+	$(CC) $(CFLAGS) -o $@ $^ $(CHRONY_OBJS:%/$*.o=) $(LDFLAGS)
+
+%.o: %.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+check: $(TESTS)
+	@ret=0; \
+	for t in $^; do \
+	  $(TEST_WRAPPER) ./$$t || ret=1; \
+	done; \
+	exit $$ret
+
+clean:
+	rm -f *.o $(TESTS)
+	rm -rf .deps
+
+distclean: clean
+	rm -f Makefile
+
+.deps:
+	@mkdir .deps
+
+.deps/%.d: %.c | .deps
+	@$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@
+
+-include $(TEST_OBJS:%.o=.deps/%.d)
diff --git a/chrony_3_3/test/unit/Makefile.in b/chrony_3_3/test/unit/Makefile.in
new file mode 100644
index 0000000..554663b
--- /dev/null
+++ b/chrony_3_3/test/unit/Makefile.in
@@ -0,0 +1,45 @@
+TEST_WRAPPER =
+CHRONY_SRCDIR = ../..
+
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPPFLAGS = -I$(CHRONY_SRCDIR) @CPPFLAGS@
+LDFLAGS = @LDFLAGS@ @LIBS@ @EXTRA_LIBS@
+
+SHARED_OBJS = test.o
+
+TEST_OBJS := $(sort $(patsubst %.c,%.o,$(wildcard *.c)))
+TESTS := $(patsubst %.o,%.test,$(filter-out $(SHARED_OBJS),$(TEST_OBJS)))
+
+FILTER_OBJS = %/main.o %/client.o %/getdate.o
+CHRONY_OBJS := $(filter-out $(FILTER_OBJS),$(wildcard $(CHRONY_SRCDIR)/*.o))
+
+all: $(TESTS)
+
+%.test: %.o $(SHARED_OBJS)
+	$(CC) $(CFLAGS) -o $@ $^ $(CHRONY_OBJS:%/$*.o=) $(LDFLAGS)
+
+%.o: %.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+check: $(TESTS)
+	@ret=0; \
+	for t in $^; do \
+	  $(TEST_WRAPPER) ./$$t || ret=1; \
+	done; \
+	exit $$ret
+
+clean:
+	rm -f *.o $(TESTS)
+	rm -rf .deps
+
+distclean: clean
+	rm -f Makefile
+
+.deps:
+	@mkdir .deps
+
+.deps/%.d: %.c | .deps
+	@$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@
+
+-include $(TEST_OBJS:%.o=.deps/%.d)
diff --git a/chrony_3_3/test/unit/addrfilt.c b/chrony_3_3/test/unit/addrfilt.c
new file mode 100644
index 0000000..b236073
--- /dev/null
+++ b/chrony_3_3/test/unit/addrfilt.c
@@ -0,0 +1,83 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+ */
+
+#include <addrfilt.c>
+#include <logging.h>
+#include <util.h>
+#include "test.h"
+
+void
+test_unit(void)
+{
+  int i, j, sub, maxsub;
+  IPAddr ip;
+  ADF_AuthTable table;
+
+  table = ADF_CreateTable();
+
+  for (i = 0; i < 100; i++) {
+    for (j = 0; j < 1000; j++) {
+      if (j % 2) {
+        maxsub = 32;
+        TST_GetRandomAddress(&ip, IPADDR_INET4, -1);
+      } else {
+        maxsub = 128;
+        TST_GetRandomAddress(&ip, IPADDR_INET6, -1);
+      }
+
+      DEBUG_LOG("address %s", UTI_IPToString(&ip));
+
+      sub = random() % (maxsub + 1);
+
+      TEST_CHECK(!ADF_IsAllowed(table, &ip));
+      ADF_Allow(table, &ip, sub);
+      TEST_CHECK(ADF_IsAllowed(table, &ip));
+
+      if (sub < maxsub) {
+        TST_SwapAddressBit(&ip, sub);
+        TEST_CHECK(ADF_IsAllowed(table, &ip));
+      }
+
+      if (sub > 0) {
+        TST_SwapAddressBit(&ip, sub - 1);
+        TEST_CHECK(!ADF_IsAllowed(table, &ip));
+        if (sub % 4 != 1) {
+          ADF_Deny(table, &ip, sub - 1);
+          TST_SwapAddressBit(&ip, sub - 1);
+          TEST_CHECK(!ADF_IsAllowed(table, &ip));
+        }
+      }
+
+      if (sub > 4) {
+        ADF_AllowAll(table, &ip, sub - 4);
+        TEST_CHECK(ADF_IsAllowed(table, &ip));
+      }
+
+      ADF_DenyAll(table, &ip, 0);
+    }
+
+    ip.family = IPADDR_INET4;
+    ADF_DenyAll(table, &ip, 0);
+    ip.family = IPADDR_INET6;
+    ADF_DenyAll(table, &ip, 0);
+  }
+
+  ADF_DestroyTable(table);
+}
diff --git a/chrony_3_3/test/unit/clientlog.c b/chrony_3_3/test/unit/clientlog.c
new file mode 100644
index 0000000..515ad1a
--- /dev/null
+++ b/chrony_3_3/test/unit/clientlog.c
@@ -0,0 +1,84 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+ */
+
+#include <clientlog.c>
+#include "test.h"
+
+void
+test_unit(void)
+{
+  int i, j, index;
+  struct timespec ts;
+  IPAddr ip;
+  char conf[][100] = {
+    "clientloglimit 10000",
+    "ratelimit interval 3 burst 4 leak 3",
+    "cmdratelimit interval 3 burst 4 leak 3",
+  };
+
+  CNF_Initialise(0, 0);
+  for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
+    CNF_ParseLine(NULL, i + 1, conf[i]);
+
+  CLG_Initialise();
+
+  TEST_CHECK(ARR_GetSize(records) == 16);
+
+  for (i = 0; i < 500; i++) {
+    DEBUG_LOG("iteration %d", i);
+
+    ts.tv_sec = (time_t)random() & 0x0fffffff;
+    ts.tv_nsec = 0;
+
+    for (j = 0; j < 1000; j++) {
+      TST_GetRandomAddress(&ip, IPADDR_UNSPEC, i % 8 ? -1 : i / 8 % 9);
+      DEBUG_LOG("address %s", UTI_IPToString(&ip));
+
+      if (random() % 2) {
+        index = CLG_LogNTPAccess(&ip, &ts);
+        TEST_CHECK(index >= 0);
+        CLG_LimitNTPResponseRate(index);
+      } else {
+        index = CLG_LogCommandAccess(&ip, &ts);
+        TEST_CHECK(index >= 0);
+        CLG_LimitCommandResponseRate(index);
+      }
+
+      UTI_AddDoubleToTimespec(&ts, (1 << random() % 14) / 100.0, &ts);
+    }
+  }
+
+  DEBUG_LOG("records %d", ARR_GetSize(records));
+  TEST_CHECK(ARR_GetSize(records) == 64);
+
+  for (i = j = 0; i < 10000; i++) {
+    ts.tv_sec += 1;
+    index = CLG_LogNTPAccess(&ip, &ts);
+    TEST_CHECK(index >= 0);
+    if (!CLG_LimitNTPResponseRate(index))
+      j++;
+  }
+
+  DEBUG_LOG("requests %u responses %u", i, j);
+  TEST_CHECK(j * 4 < i && j * 6 > i);
+
+  CLG_Finalise();
+  CNF_Finalise();
+}
diff --git a/chrony_3_3/test/unit/hash.c b/chrony_3_3/test/unit/hash.c
new file mode 100644
index 0000000..2275473
--- /dev/null
+++ b/chrony_3_3/test/unit/hash.c
@@ -0,0 +1,123 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+ */
+
+#include <config.h>
+#include <sysincl.h>
+#include <hash.h>
+#include <logging.h>
+#include "test.h"
+
+struct hash_test {
+  const char *name;
+  const unsigned char out[MAX_HASH_LENGTH];
+  unsigned int length;
+};
+
+void
+test_unit(void)
+{
+  unsigned char data1[] = "abcdefghijklmnopqrstuvwxyz";
+  unsigned char data2[] = "12345678910";
+  unsigned char out[MAX_HASH_LENGTH];
+  struct hash_test tests[] = {
+    { "MD5",       "\xfc\x24\x97\x1b\x52\x66\xdc\x46\xef\xe0\xe8\x08\x46\x89\xb6\x88", 16 },
+    { "SHA1",      "\xd8\x85\xb3\x86\xce\xea\x93\xeb\x92\xcd\x7b\x94\xb9\x8d\xc2\x8e"
+                   "\x3e\x31\x13\xdd", 20},
+    { "SHA256",    "\x0e\x35\x14\xe7\x15\x7a\x1d\xdd\xea\x11\x78\xd3\x41\xf6\xb9\x3e"
+                   "\xa0\x42\x96\x73\x3c\x54\x74\x0b\xfa\x6b\x9e\x29\x59\xad\x69\xd3", 32 },
+    { "SHA384",    "\x2c\xeb\xbd\x4d\x95\xed\xad\x03\xed\x80\xc4\xf3\xa6\x10\x21\xde"
+                   "\x40\x69\x54\xed\x42\x70\xb8\x95\xb0\x6f\x01\x1d\x04\xdf\x57\xbc"
+                   "\x1d\xb5\x85\xbf\x4f\x03\x88\xd5\x83\x93\xbc\x81\x90\xb0\xa9\x9b", 48 },
+    { "SHA512",    "\x20\xba\xec\xcb\x68\x98\x33\x5b\x70\x26\x63\x13\xe2\xf7\x0e\x67"
+                   "\x08\xf3\x77\x4f\xbd\xeb\xc4\xa8\xc5\x94\xe2\x39\x40\x7e\xed\x0b"
+                   "\x69\x0e\x18\xa5\xa2\x03\x73\xe7\x1d\x20\x7d\x3f\xc8\x70\x2d\x64"
+                   "\x9e\x89\x6d\x20\x6a\x4a\x5a\x46\xe7\x4f\x2c\xf9\x0f\x0a\x54\xdc", 64 },
+    { "SHA3-224",  "\x3b\xa2\x22\x28\xdd\x26\x18\xec\x3b\xb9\x25\x39\x5e\xbd\x94\x25"
+                   "\xd4\x20\x8a\x76\x76\xc0\x3c\x5d\x9e\x0a\x06\x46", 28},
+    { "SHA3-256",  "\x26\xd1\x19\xb2\xc1\x64\xc8\xb8\x10\xd8\xa8\x1c\xb6\xa4\x0d\x29"
+                   "\x09\xc9\x8e\x2e\x2d\xde\x7a\x74\x8c\x43\x70\xb8\xaa\x0f\x09\x17", 32 },
+    { "SHA3-384",  "\x6a\x64\xb9\x89\x08\x29\xd0\xa7\x4b\x84\xba\xa6\x65\xf5\xe7\x54"
+                   "\xe2\x18\x12\xc3\x63\x34\xc6\xba\x26\xf5\x6e\x99\xe2\x54\xcc\x9d"
+                   "\x01\x10\x9d\xee\x35\x38\x04\x83\xe5\x71\x70\xd8\xc8\x99\x96\xd8", 48 },
+    { "SHA3-512",  "\xa8\xe3\x2b\x65\x1f\x87\x90\x73\x19\xc8\xa0\x3f\xe3\x85\x60\x3c"
+                   "\x39\xfc\xcb\xc1\x29\xe1\x23\x7d\x8b\x56\x54\xe3\x08\x9d\xf9\x74"
+                   "\x78\x69\x2e\x3c\x7e\x51\x1e\x9d\xab\x09\xbe\xe7\x6b\x1a\xa1\x22"
+                   "\x93\xb1\x2b\x82\x9d\x1e\xcf\xa8\x99\xc5\xec\x7b\x1d\x89\x07\x2b", 64 },
+    { "RMD128",    "\x6f\xd7\x1f\x37\x47\x0f\xbd\x42\x57\xc8\xbb\xee\xba\x65\xf9\x35", 16 },
+    { "RMD160",    "\x7a\x88\xec\xc7\x09\xc5\x65\x34\x11\x24\xe3\xf9\xf7\xa5\xbf\xc6"
+                   "\x01\xe2\xc9\x32", 20},
+    { "RMD256",    "\x59\xdf\xd4\xcb\xc9\xbe\x7c\x27\x08\xa7\x23\xf7\xb3\x0c\xf0\x0d"
+                   "\xa0\xcf\x5b\x18\x16\x51\x56\x6d\xda\x7b\x87\x24\x9d\x83\x35\xe1", 32 },
+    { "RMD320",    "\x68\x98\x10\xf4\xb6\x79\xb6\x15\xf1\x48\x2d\x73\xd0\x23\x84\x01"
+                   "\xbf\xaa\x67\xcf\x1e\x35\x5c\xbf\xe9\xb8\xaf\xe1\xee\x0d\xf0\x6b"
+                   "\xe2\x3a\x9a\x3a\xa7\x56\xad\x70", 40},
+    { "TIGER",     "\x1c\xcd\x68\x74\xca\xd6\xd5\x17\xba\x3e\x82\xaf\xbd\x70\xdc\x66"
+                   "\x99\xaa\xae\x16\x72\x59\xd1\x64", 24},
+    { "WHIRLPOOL", "\xe3\xcd\xe6\xbf\xe1\x8c\xe4\x4d\xc8\xb4\xa5\x7c\x36\x8d\xc8\x8a"
+                   "\x8b\xad\x52\x24\xc0\x4e\x99\x5b\x7e\x86\x94\x2d\x10\x56\x12\xa3"
+                   "\x29\x2a\x65\x0f\x9e\x07\xbc\x15\x21\x14\xe6\x07\xfc\xe6\xb9\x2f"
+                   "\x13\xe2\x57\xe9\x0a\xb0\xd2\xf4\xa3\x20\x36\x9c\x88\x92\x8e\xc9", 64 },
+    { "", "", 0 }
+  };
+
+  unsigned int length;
+  int i, j, hash_id;
+
+  for (i = 0; tests[i].name[0] != '\0'; i++) {
+    hash_id = HSH_GetHashId(tests[i].name);
+    if (hash_id < 0) {
+      TEST_CHECK(strcmp(tests[i].name, "MD5"));
+#ifdef FEAT_SECHASH
+      TEST_CHECK(strcmp(tests[i].name, "SHA1"));
+      TEST_CHECK(strcmp(tests[i].name, "SHA256"));
+      TEST_CHECK(strcmp(tests[i].name, "SHA384"));
+      TEST_CHECK(strcmp(tests[i].name, "SHA512"));
+#endif
+      continue;
+    }
+
+    DEBUG_LOG("testing %s", tests[i].name);
+
+    for (j = 0; j <= sizeof (out); j++) {
+      TEST_CHECK(HSH_GetHashId(tests[i].name) == hash_id);
+      TEST_CHECK(HSH_GetHashId("nosuchhash") < 0);
+
+      memset(out, 0, sizeof (out));
+      length = HSH_Hash(hash_id, data1, sizeof (data1) - 1, data2, sizeof (data2) - 1,
+                        out, j);
+
+      if (j >= tests[i].length)
+        TEST_CHECK(length == tests[i].length);
+      else
+        TEST_CHECK(length == 0 || length == j || length == tests[i].length);
+
+      TEST_CHECK(!memcmp(out, tests[i].out, length));
+    }
+
+    for (j = 0; j < 10000; j++) {
+      length = HSH_Hash(hash_id, data1, random() % sizeof (data1),
+                        random() % 2 ? data2 : NULL, random() % sizeof (data2),
+                        out, sizeof (out));
+      TEST_CHECK(length == tests[i].length);
+    }
+  }
+
+  HSH_Finalise();
+}
diff --git a/chrony_3_3/test/unit/hwclock.c b/chrony_3_3/test/unit/hwclock.c
new file mode 100644
index 0000000..1cbd312
--- /dev/null
+++ b/chrony_3_3/test/unit/hwclock.c
@@ -0,0 +1,82 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2016-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.
+ * 
+ **********************************************************************
+ */
+
+#include <hwclock.c>
+#include "test.h"
+
+void
+test_unit(void)
+{
+  struct timespec start_hw_ts, start_local_ts, hw_ts, local_ts, ts;
+  HCL_Instance clock;
+  double freq, jitter, interval, dj, sum;
+  int i, j, count;
+
+  LCL_Initialise();
+
+  clock = HCL_CreateInstance(1.0);
+
+  for (i = 0, count = 0, sum = 0.0; i < 2000; i++) {
+    UTI_ZeroTimespec(&start_hw_ts);
+    UTI_ZeroTimespec(&start_local_ts);
+    UTI_AddDoubleToTimespec(&start_hw_ts, TST_GetRandomDouble(0.0, 1e9), &start_hw_ts);
+    UTI_AddDoubleToTimespec(&start_local_ts, TST_GetRandomDouble(0.0, 1e9), &start_local_ts);
+
+    DEBUG_LOG("iteration %d", i);
+
+    freq = TST_GetRandomDouble(0.9, 1.1);
+    jitter = TST_GetRandomDouble(10.0e-9, 1000.0e-9);
+    interval = TST_GetRandomDouble(0.1, 10.0);
+
+    clock->n_samples = 0;
+    clock->valid_coefs = 0;
+
+    for (j = 0; j < 100; j++) {
+      UTI_AddDoubleToTimespec(&start_hw_ts, j * interval * freq, &hw_ts);
+      UTI_AddDoubleToTimespec(&start_local_ts, j * interval, &local_ts);
+      if (HCL_CookTime(clock, &hw_ts, &ts, NULL)) {
+        dj = fabs(UTI_DiffTimespecsToDouble(&ts, &local_ts) / jitter);
+        DEBUG_LOG("delta/jitter %f", dj);
+        if (clock->n_samples >= 8)
+          sum += dj, count++;
+        TEST_CHECK(clock->n_samples < 4 || dj <= 4.0);
+        TEST_CHECK(clock->n_samples < 8 || dj <= 3.0);
+      }
+
+      UTI_AddDoubleToTimespec(&start_hw_ts, j * interval * freq + TST_GetRandomDouble(-jitter, jitter), &hw_ts);
+
+      if (HCL_NeedsNewSample(clock, &local_ts))
+        HCL_AccumulateSample(clock, &hw_ts, &local_ts, 2.0 * jitter);
+
+      TEST_CHECK(clock->valid_coefs || clock->n_samples < 2);
+
+      if (!clock->valid_coefs)
+        continue;
+
+      TEST_CHECK(fabs(clock->offset) <= 2.0 * jitter);
+    }
+  }
+
+  TEST_CHECK(sum / count < 0.4);
+
+  HCL_DestroyInstance(clock);
+
+  LCL_Finalise();
+}
diff --git a/chrony_3_3/test/unit/keys.c b/chrony_3_3/test/unit/keys.c
new file mode 100644
index 0000000..ac995fa
--- /dev/null
+++ b/chrony_3_3/test/unit/keys.c
@@ -0,0 +1,147 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+ */
+
+#include <keys.c>
+#include "test.h"
+
+#define KEYS 100
+#define KEYFILE "keys.test-keys"
+
+static
+uint32_t write_random_key(FILE *f)
+{
+  const char *hash_name;
+  char key[128];
+  uint32_t id;
+  int i, length;
+
+  length = random() % sizeof (key) + 1;
+  length = MAX(length, 4);
+  UTI_GetRandomBytes(&id, sizeof (id));
+  UTI_GetRandomBytes(key, length);
+
+  switch (random() % 6) {
+#ifdef FEAT_SECHASH
+    case 0:
+      hash_name = "SHA1";
+      break;
+    case 1:
+      hash_name = "SHA256";
+      break;
+    case 2:
+      hash_name = "SHA384";
+      break;
+    case 3:
+      hash_name = "SHA512";
+      break;
+#endif
+    case 4:
+      hash_name = "MD5";
+      break;
+    default:
+      hash_name = "";
+  }
+
+  fprintf(f, "%u %s %s", id, hash_name, random() % 2 ? "HEX:" : "");
+  for (i = 0; i < length; i++)
+    fprintf(f, "%02hhX", key[i]);
+  fprintf(f, "\n");
+
+  return id;
+}
+
+static void
+generate_key_file(const char *name, uint32_t *keys)
+{
+  FILE *f;
+  int i;
+
+  f = fopen(name, "w");
+  TEST_CHECK(f);
+  for (i = 0; i < KEYS; i++)
+    keys[i] = write_random_key(f);
+  fclose(f);
+}
+
+void
+test_unit(void)
+{
+  int i, j, data_len, auth_len;
+  uint32_t keys[KEYS], key;
+  unsigned char data[100], auth[MAX_HASH_LENGTH];
+  char conf[][100] = {
+    "keyfile "KEYFILE
+  };
+
+  CNF_Initialise(0, 0);
+  for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
+    CNF_ParseLine(NULL, i + 1, conf[i]);
+
+  generate_key_file(KEYFILE, keys);
+  KEY_Initialise();
+
+  for (i = 0; i < 100; i++) {
+    DEBUG_LOG("iteration %d", i);
+
+    if (i) {
+      generate_key_file(KEYFILE, keys);
+      KEY_Reload();
+    }
+
+    UTI_GetRandomBytes(data, sizeof (data));
+
+    for (j = 0; j < KEYS; j++) {
+      TEST_CHECK(KEY_KeyKnown(keys[j]));
+      TEST_CHECK(KEY_GetAuthDelay(keys[j]) >= 0);
+      TEST_CHECK(KEY_GetAuthLength(keys[j]) >= 16);
+
+      data_len = random() % (sizeof (data) + 1);
+      auth_len = KEY_GenerateAuth(keys[j], data, data_len, auth, sizeof (auth));
+      TEST_CHECK(auth_len >= 16);
+
+      TEST_CHECK(KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
+
+      if (j > 0 && keys[j - 1] != keys[j])
+        TEST_CHECK(!KEY_CheckAuth(keys[j - 1], data, data_len, auth, auth_len, auth_len));
+
+      auth_len = random() % auth_len + 1;
+      if (auth_len < MAX_HASH_LENGTH)
+        auth[auth_len]++;
+      TEST_CHECK(KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
+
+      auth[auth_len - 1]++;
+      TEST_CHECK(!KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
+    }
+
+    for (j = 0; j < 1000; j++) {
+      UTI_GetRandomBytes(&key, sizeof (key));
+      if (KEY_KeyKnown(key))
+        continue;
+      TEST_CHECK(!KEY_GenerateAuth(key, data, data_len, auth, sizeof (auth)));
+      TEST_CHECK(!KEY_CheckAuth(key, data, data_len, auth, auth_len, auth_len));
+    }
+  }
+
+  unlink(KEYFILE);
+
+  KEY_Finalise();
+  CNF_Finalise();
+  HSH_Finalise();
+}
diff --git a/chrony_3_3/test/unit/ntp_core.c b/chrony_3_3/test/unit/ntp_core.c
new file mode 100644
index 0000000..074c4d7
--- /dev/null
+++ b/chrony_3_3/test/unit/ntp_core.c
@@ -0,0 +1,444 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2017-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.
+ * 
+ **********************************************************************
+ */
+
+#include <config.h>
+#include <sysincl.h>
+#include <cmdparse.h>
+#include <conf.h>
+#include <keys.h>
+#include <ntp_io.h>
+#include <sched.h>
+#include <local.h>
+#include "test.h"
+
+static struct timespec current_time;
+static NTP_Receive_Buffer req_buffer, res_buffer;
+static int req_length, res_length;
+
+#define NIO_OpenServerSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 100 : 0)
+#define NIO_CloseServerSocket(fd) assert(fd == 100)
+#define NIO_OpenClientSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 101 : 0)
+#define NIO_CloseClientSocket(fd) assert(fd == 101)
+#define NIO_IsServerSocket(fd) (fd == 100)
+#define NIO_SendPacket(msg, to, from, len, process_tx) (memcpy(&req_buffer, msg, len), req_length = len, 1)
+#define SCH_AddTimeoutByDelay(delay, handler, arg) (1 ? 102 : (handler(arg), 1))
+#define SCH_AddTimeoutInClass(delay, separation, randomness, class, handler, arg) \
+  add_timeout_in_class(delay, separation, randomness, class, handler, arg)
+#define SCH_RemoveTimeout(id) assert(!id || id == 102)
+#define LCL_ReadRawTime(ts) (*ts = current_time)
+#define LCL_ReadCookedTime(ts, err) do {double *p = err; *ts = current_time; if (p) *p = 0.0;} while (0)
+#define LCL_GetSysPrecisionAsLog() (random() % 10 - 30)
+#define SRC_UpdateReachability(inst, reach)
+#define SRC_ResetReachability(inst)
+
+static SCH_TimeoutID
+add_timeout_in_class(double min_delay, double separation, double randomness,
+                     SCH_TimeoutClass class, SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg)
+{
+  return 102;
+}
+
+#include <ntp_core.c>
+
+static void
+advance_time(double x)
+{
+  UTI_AddDoubleToTimespec(&current_time, x, &current_time);
+}
+
+static void
+send_request(NCR_Instance inst)
+{
+  NTP_Local_Address local_addr;
+  NTP_Local_Timestamp local_ts;
+  uint32_t prev_tx_count;
+
+  prev_tx_count = inst->report.total_tx_count;
+
+  transmit_timeout(inst);
+  TEST_CHECK(!inst->valid_rx);
+  TEST_CHECK(prev_tx_count + 1 == inst->report.total_tx_count);
+
+  advance_time(1e-5);
+
+  if (random() % 2) {
+    local_addr.ip_addr.family = IPADDR_UNSPEC;
+    local_addr.if_index = INVALID_IF_INDEX;
+    local_addr.sock_fd = 101;
+    local_ts.ts = current_time;
+    local_ts.err = 0.0;
+    local_ts.source = NTP_TS_KERNEL;
+
+    NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer.ntp_pkt, req_length);
+  }
+}
+
+static void
+process_request(NTP_Remote_Address *remote_addr)
+{
+  NTP_Local_Address local_addr;
+  NTP_Local_Timestamp local_ts;
+
+  local_addr.ip_addr.family = IPADDR_UNSPEC;
+  local_addr.if_index = INVALID_IF_INDEX;
+  local_addr.sock_fd = 100;
+  local_ts.ts = current_time;
+  local_ts.err = 0.0;
+  local_ts.source = NTP_TS_KERNEL;
+
+  res_length = 0;
+  NCR_ProcessRxUnknown(remote_addr, &local_addr, &local_ts,
+                       &req_buffer.ntp_pkt, req_length);
+  res_length = req_length;
+  res_buffer = req_buffer;
+
+  advance_time(1e-5);
+
+  if (random() % 2) {
+    local_ts.ts = current_time;
+    NCR_ProcessTxUnknown(remote_addr, &local_addr, &local_ts,
+                         &res_buffer.ntp_pkt, res_length);
+  }
+}
+
+static void
+send_response(int interleaved, int authenticated, int allow_update, int valid_ts, int valid_auth)
+{
+  NTP_Packet *req, *res;
+
+  req = &req_buffer.ntp_pkt;
+  res = &res_buffer.ntp_pkt;
+
+  TEST_CHECK(req_length >= NTP_NORMAL_PACKET_LENGTH);
+
+  res->lvm = NTP_LVM(LEAP_Normal, NTP_LVM_TO_VERSION(req->lvm),
+                     NTP_LVM_TO_MODE(req->lvm) == MODE_CLIENT ? MODE_SERVER : MODE_ACTIVE);
+  res->stratum = 1;
+  res->poll = req->poll;
+  res->precision = -20;
+  res->root_delay = UTI_DoubleToNtp32(0.1);
+  res->root_dispersion = UTI_DoubleToNtp32(0.1);
+  res->reference_id = 0;
+  UTI_ZeroNtp64(&res->reference_ts);
+  res->originate_ts = interleaved ? req->receive_ts : req->transmit_ts;
+
+  advance_time(TST_GetRandomDouble(1e-4, 1e-2));
+  UTI_TimespecToNtp64(&current_time, &res->receive_ts, NULL);
+  advance_time(TST_GetRandomDouble(-1e-4, 1e-3));
+  UTI_TimespecToNtp64(&current_time, &res->transmit_ts, NULL);
+  advance_time(TST_GetRandomDouble(1e-4, 1e-2));
+
+  if (!valid_ts) {
+    switch (random() % (allow_update ? 4 : 5)) {
+      case 0:
+        res->originate_ts.hi = random();
+        break;
+      case 1:
+        res->originate_ts.lo = random();
+        break;
+      case 2:
+        UTI_ZeroNtp64(&res->originate_ts);
+        break;
+      case 3:
+        UTI_ZeroNtp64(&res->receive_ts);
+        break;
+      case 4:
+        UTI_ZeroNtp64(&res->transmit_ts);
+        break;
+      default:
+        assert(0);
+    }
+  }
+
+  if (authenticated) {
+    res->auth_keyid = req->auth_keyid;
+    KEY_GenerateAuth(ntohl(res->auth_keyid), (unsigned char *)res, NTP_NORMAL_PACKET_LENGTH,
+                     res->auth_data, 16);
+    res_length = NTP_NORMAL_PACKET_LENGTH + 4 + 16;
+  } else {
+    res_length = NTP_NORMAL_PACKET_LENGTH;
+  }
+
+  if (!valid_auth) {
+    switch (random() % 3) {
+      case 0:
+        res->auth_keyid++;
+        break;
+      case 1:
+        res->auth_data[random() % 16]++;
+        break;
+      case 2:
+        res_length = NTP_NORMAL_PACKET_LENGTH;
+        break;
+      default:
+        assert(0);
+    }
+  }
+}
+
+static void
+process_response(NCR_Instance inst, int good, int valid, int updated_sync, int updated_init)
+{
+  NTP_Local_Address local_addr;
+  NTP_Local_Timestamp local_ts;
+  NTP_Packet *res;
+  uint32_t prev_rx_count, prev_valid_count;
+  struct timespec prev_rx_ts, prev_init_rx_ts;
+  int prev_open_socket, ret;
+
+  res = &res_buffer.ntp_pkt;
+
+  local_addr.ip_addr.family = IPADDR_UNSPEC;
+  local_addr.if_index = INVALID_IF_INDEX;
+  local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) != MODE_SERVER ? 100 : 101;
+  local_ts.ts = current_time;
+  local_ts.err = 0.0;
+  local_ts.source = NTP_TS_KERNEL;
+
+  prev_rx_count = inst->report.total_rx_count;
+  prev_valid_count = inst->report.total_valid_count;
+  prev_rx_ts = inst->local_rx.ts;
+  prev_init_rx_ts = inst->init_local_rx.ts;
+  prev_open_socket = inst->local_addr.sock_fd != INVALID_SOCK_FD;
+
+  ret = NCR_ProcessRxKnown(inst, &local_addr, &local_ts, res, res_length);
+
+  if (good > 0)
+    TEST_CHECK(ret);
+  else if (!good)
+    TEST_CHECK(!ret);
+
+  if (prev_open_socket)
+    TEST_CHECK(prev_rx_count + 1 == inst->report.total_rx_count);
+  else
+    TEST_CHECK(prev_rx_count == inst->report.total_rx_count);
+
+  if (valid)
+    TEST_CHECK(prev_valid_count + 1 == inst->report.total_valid_count);
+  else
+    TEST_CHECK(prev_valid_count == inst->report.total_valid_count);
+
+  if (updated_sync)
+    TEST_CHECK(UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
+  else
+    TEST_CHECK(!UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
+
+  if (updated_init > 0)
+    TEST_CHECK(UTI_CompareTimespecs(&inst->init_local_rx.ts, &prev_init_rx_ts));
+  else if (!updated_init)
+    TEST_CHECK(!UTI_CompareTimespecs(&inst->init_local_rx.ts, &prev_init_rx_ts));
+
+  if (valid) {
+    TEST_CHECK(UTI_IsZeroTimespec(&inst->init_local_rx.ts));
+    TEST_CHECK(UTI_IsZeroNtp64(&inst->init_remote_ntp_tx));
+  }
+}
+
+static void
+process_replay(NCR_Instance inst, NTP_Receive_Buffer *packet_queue,
+               int queue_length, int updated_init)
+{
+  do {
+    res_buffer = packet_queue[random() % queue_length];
+  } while (!UTI_CompareNtp64(&res_buffer.ntp_pkt.transmit_ts,
+                             &inst->remote_ntp_tx));
+  process_response(inst, 0, 0, 0, updated_init);
+  advance_time(1e-6);
+}
+
+#define PACKET_QUEUE_LENGTH 10
+
+void
+test_unit(void)
+{
+  char source_line[] = "127.0.0.1 maxdelaydevratio 1e6";
+  char conf[][100] = {
+    "allow",
+    "port 0",
+    "local",
+    "keyfile ntp_core.keys"
+  };
+  int i, j, k, interleaved, authenticated, valid, updated, has_updated;
+  CPS_NTP_Source source;
+  NTP_Remote_Address remote_addr;
+  NCR_Instance inst1, inst2;
+  NTP_Receive_Buffer packet_queue[PACKET_QUEUE_LENGTH];
+
+  CNF_Initialise(0, 0);
+  for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
+    CNF_ParseLine(NULL, i + 1, conf[i]);
+
+  LCL_Initialise();
+  TST_RegisterDummyDrivers();
+  SCH_Initialise();
+  SRC_Initialise();
+  NIO_Initialise(IPADDR_UNSPEC);
+  NCR_Initialise();
+  REF_Initialise();
+  KEY_Initialise();
+
+  CNF_SetupAccessRestrictions();
+
+  CPS_ParseNTPSourceAdd(source_line, &source);
+
+  for (i = 0; i < 1000; i++) {
+    if (random() % 2)
+      source.params.interleaved = 1;
+    if (random() % 2)
+      source.params.authkey = 1;
+    source.params.version = random() % 4 + 1;
+
+    UTI_ZeroTimespec(&current_time);
+    advance_time(TST_GetRandomDouble(1.0, 1e9));
+
+    TST_GetRandomAddress(&remote_addr.ip_addr, IPADDR_UNSPEC, -1);
+    remote_addr.port = 123;
+
+    inst1 = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
+    NCR_StartInstance(inst1);
+    has_updated = 0;
+
+    for (j = 0; j < 50; j++) {
+      DEBUG_LOG("client/peer test iteration %d/%d", i, j);
+
+      interleaved = random() % 2 && (inst1->mode != MODE_CLIENT ||
+                                     inst1->tx_count < MAX_CLIENT_INTERLEAVED_TX);
+      authenticated = random() % 2;
+      valid = (!interleaved || (source.params.interleaved && has_updated)) &&
+              (!source.params.authkey || authenticated);
+      updated = (valid || inst1->mode == MODE_ACTIVE) &&
+                (!source.params.authkey || authenticated);
+      has_updated = has_updated || updated;
+      if (inst1->mode == MODE_CLIENT)
+        updated = 0;
+
+      send_request(inst1);
+
+      send_response(interleaved, authenticated, 1, 0, 1);
+      DEBUG_LOG("response 1");
+      process_response(inst1, 0, 0, 0, updated);
+
+      if (source.params.authkey) {
+        send_response(interleaved, authenticated, 1, 1, 0);
+        DEBUG_LOG("response 2");
+        process_response(inst1, 0, 0, 0, 0);
+      }
+
+      send_response(interleaved, authenticated, 1, 1, 1);
+      DEBUG_LOG("response 3");
+      process_response(inst1, -1, valid, valid, updated);
+      DEBUG_LOG("response 4");
+      process_response(inst1, 0, 0, 0, 0);
+
+      advance_time(-1.0);
+
+      send_response(interleaved, authenticated, 1, 1, 1);
+      DEBUG_LOG("response 5");
+      process_response(inst1, 0, 0, 0, updated && valid);
+
+      advance_time(1.0);
+
+      send_response(interleaved, authenticated, 1, 1, 1);
+      DEBUG_LOG("response 6");
+      process_response(inst1, 0, 0, valid && updated, updated);
+    }
+
+    NCR_DestroyInstance(inst1);
+
+    inst1 = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
+    NCR_StartInstance(inst1);
+
+    for (j = 0; j < 20; j++) {
+      DEBUG_LOG("server test iteration %d/%d", i, j);
+
+      send_request(inst1);
+      process_request(&remote_addr);
+      process_response(inst1, 1, 1, 1, 0);
+      advance_time(1 << inst1->local_poll);
+    }
+
+    NCR_DestroyInstance(inst1);
+
+    inst1 = NCR_GetInstance(&remote_addr, NTP_PEER, &source.params);
+    NCR_StartInstance(inst1);
+    inst2 = NCR_GetInstance(&remote_addr, NTP_PEER, &source.params);
+    NCR_StartInstance(inst2);
+
+    res_length = req_length = 0;
+
+    for (j = 0; j < 20; j++) {
+      DEBUG_LOG("peer replay test iteration %d/%d", i, j);
+
+      send_request(inst1);
+      res_buffer = req_buffer;
+      assert(!res_length || res_length == req_length);
+      res_length = req_length;
+
+      TEST_CHECK(inst1->valid_timestamps == (j > 0));
+
+      DEBUG_LOG("response 1->2");
+      process_response(inst2, j > source.params.interleaved, j > 0, j > 0, 1);
+
+      packet_queue[(j * 2) % PACKET_QUEUE_LENGTH] = res_buffer;
+
+      for (k = 0; k < j % 4 + 1; k++) {
+        DEBUG_LOG("replay ?->1 %d", k);
+        process_replay(inst1, packet_queue, MIN(j * 2 + 1, PACKET_QUEUE_LENGTH), k ? -1 : 1);
+        DEBUG_LOG("replay ?->2 %d", k);
+        process_replay(inst2, packet_queue, MIN(j * 2 + 1, PACKET_QUEUE_LENGTH), -1);
+      }
+
+      advance_time(1 << (source.params.minpoll - 1));
+
+      send_request(inst2);
+      res_buffer = req_buffer;
+      assert(res_length == req_length);
+
+      TEST_CHECK(inst2->valid_timestamps == (j > 0));
+
+      DEBUG_LOG("response 2->1");
+      process_response(inst1, 1, 1, 1, 1);
+
+      packet_queue[(j * 2 + 1) % PACKET_QUEUE_LENGTH] = res_buffer;
+
+      for (k = 0; k < j % 4 + 1; k++) {
+        DEBUG_LOG("replay ?->1 %d", k);
+        process_replay(inst1, packet_queue, MIN(j * 2 + 2, PACKET_QUEUE_LENGTH), k ? -1 : 1);
+        DEBUG_LOG("replay ?->2 %d", k);
+        process_replay(inst2, packet_queue, MIN(j * 2 + 2, PACKET_QUEUE_LENGTH), -1);
+      }
+
+      advance_time(1 << (source.params.minpoll - 1));
+    }
+
+    NCR_DestroyInstance(inst1);
+    NCR_DestroyInstance(inst2);
+  }
+
+  KEY_Finalise();
+  REF_Finalise();
+  NCR_Finalise();
+  NIO_Finalise();
+  SRC_Finalise();
+  SCH_Finalise();
+  LCL_Finalise();
+  CNF_Finalise();
+  HSH_Finalise();
+}
diff --git a/chrony_3_3/test/unit/ntp_core.keys b/chrony_3_3/test/unit/ntp_core.keys
new file mode 100644
index 0000000..7a70e52
--- /dev/null
+++ b/chrony_3_3/test/unit/ntp_core.keys
@@ -0,0 +1,2 @@
+1 MD5 HEX:38979C567358C0896F4D9D459A3C8B8478654579
+2 MD5 HEX:38979C567358C0896F4D9D459A3C8B8478654579
diff --git a/chrony_3_3/test/unit/ntp_sources.c b/chrony_3_3/test/unit/ntp_sources.c
new file mode 100644
index 0000000..ea8f19c
--- /dev/null
+++ b/chrony_3_3/test/unit/ntp_sources.c
@@ -0,0 +1,100 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+ */
+
+#include <ntp_sources.c>
+#include <conf.h>
+#include <ntp_io.h>
+#include "test.h"
+
+void
+test_unit(void)
+{
+  int i, j, k, slot, found;
+  uint32_t hash = 0;
+  NTP_Remote_Address addrs[256], addr;
+  SourceParameters params;
+  char conf[] = "port 0";
+
+  memset(&params, 0, sizeof (params));
+
+  CNF_Initialise(0, 0);
+  CNF_ParseLine(NULL, 1, conf);
+
+  LCL_Initialise();
+  SCH_Initialise();
+  SRC_Initialise();
+  NIO_Initialise(IPADDR_UNSPEC);
+  NCR_Initialise();
+  NSR_Initialise();
+
+  for (i = 0; i < 6; i++) {
+    TEST_CHECK(ARR_GetSize(records) == 1);
+
+    DEBUG_LOG("collision mod %u", 1U << i);
+
+    for (j = 0; j < sizeof (addrs) / sizeof (addrs[0]); j++) {
+      do {
+        TST_GetRandomAddress(&addrs[j].ip_addr, IPADDR_UNSPEC, -1);
+      } while (UTI_IPToHash(&addrs[j].ip_addr) % (1U << i) != hash % (1U << i));
+
+      addrs[j].port = random() % 1024;
+
+      if (!j)
+        hash = UTI_IPToHash(&addrs[j].ip_addr);
+
+      DEBUG_LOG("adding source %s hash %"PRIu32, UTI_IPToString(&addrs[j].ip_addr),
+                UTI_IPToHash(&addrs[j].ip_addr) % (1U << i));
+
+      NSR_AddSource(&addrs[j], random() % 2 ? NTP_SERVER : NTP_PEER, &params);
+
+      for (k = 0; k < j; k++) {
+        addr = addrs[k];
+        find_slot(&addr, &slot, &found);
+        TEST_CHECK(found == 2);
+        TEST_CHECK(!UTI_CompareIPs(&get_record(slot)->remote_addr->ip_addr,
+                                   &addr.ip_addr, NULL));
+        addr.port++;
+        find_slot(&addr, &slot, &found);
+        TEST_CHECK(found == 1);
+        TEST_CHECK(!UTI_CompareIPs(&get_record(slot)->remote_addr->ip_addr,
+                                   &addr.ip_addr, NULL));
+      }
+    }
+
+    for (j = 0; j < sizeof (addrs) / sizeof (addrs[0]); j++) {
+      DEBUG_LOG("removing source %s", UTI_IPToString(&addrs[j].ip_addr));
+      NSR_RemoveSource(&addrs[j]);
+
+      for (k = 0; k < sizeof (addrs) / sizeof (addrs[0]); k++) {
+        find_slot(&addrs[k], &slot, &found);
+        TEST_CHECK(found == (k <= j ? 0 : 2));
+      }
+    }
+  }
+
+  NSR_Finalise();
+  NCR_Finalise();
+  NIO_Finalise();
+  SRC_Finalise();
+  SCH_Finalise();
+  LCL_Finalise();
+  CNF_Finalise();
+  HSH_Finalise();
+}
diff --git a/chrony_3_3/test/unit/regress.c b/chrony_3_3/test/unit/regress.c
new file mode 100644
index 0000000..f47d1c4
--- /dev/null
+++ b/chrony_3_3/test/unit/regress.c
@@ -0,0 +1,119 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+ */
+#include <regress.c>
+#include "test.h"
+
+#define POINTS 64
+
+void
+test_unit(void)
+{
+  double x[POINTS], x2[POINTS], y[POINTS], w[POINTS];
+  double b0, b1, b2, s2, sb0, sb1, slope, slope2, intercept, sd, median;
+  double xrange, yrange, wrange, x2range;
+  int i, j, n, m, c1, c2, c3, runs, best_start, dof;
+
+  for (n = 3; n <= POINTS; n++) {
+    for (i = 0; i < 200; i++) {
+      slope = TST_GetRandomDouble(-0.1, 0.1);
+      intercept = TST_GetRandomDouble(-1.0, 1.0);
+      sd = TST_GetRandomDouble(1e-6, 1e-4);
+      slope2 = (random() % 2 ? 1 : -1) * TST_GetRandomDouble(0.1, 0.5);
+
+      DEBUG_LOG("iteration %d n=%d intercept=%e slope=%e sd=%e",
+                i, n, intercept, slope, sd);
+
+      for (j = 0; j < n; j++) {
+        x[j] = -j;
+        y[j] = intercept + slope * x[j] + (j % 2 ? 1 : -1) * TST_GetRandomDouble(1e-6, sd);
+        w[j] = TST_GetRandomDouble(1.0, 2.0);
+        x2[j] = (y[j] - intercept - slope * x[j]) / slope2;
+      }
+
+      RGR_WeightedRegression(x, y, w, n, &b0, &b1, &s2, &sb0, &sb1);
+      DEBUG_LOG("WR b0=%e b1=%e s2=%e sb0=%e sb1=%e", b0, b1, s2, sb0, sb1);
+      TEST_CHECK(fabs(b0 - intercept) < sd + 1e-3);
+      TEST_CHECK(fabs(b1 - slope) < sd);
+
+      if (RGR_FindBestRegression(x, y, w, n, 0, 3, &b0, &b1, &s2, &sb0, &sb1,
+                                 &best_start, &runs, &dof)) {
+        DEBUG_LOG("BR b0=%e b1=%e s2=%e sb0=%e sb1=%e runs=%d bs=%d dof=%d",
+                  b0, b1, s2, sb0, sb1, runs, best_start, dof);
+
+        TEST_CHECK(fabs(b0 - intercept) < sd + 1e-3);
+        TEST_CHECK(fabs(b1 - slope) < sd);
+      }
+
+      if (RGR_MultipleRegress(x, x2, y, n, &b2)) {
+        DEBUG_LOG("MR b2=%e", b2);
+        TEST_CHECK(fabs(b2 - slope2) < 1e-6);
+      }
+
+      for (j = 0; j < n / 7; j++)
+        y[random() % n] += 100 * sd;
+
+      if (RGR_FindBestRobustRegression(x, y, n, 1e-8, &b0, &b1, &runs, &best_start)) {
+        DEBUG_LOG("BRR b0=%e b1=%e runs=%d bs=%d", b0, b1, runs, best_start);
+
+        TEST_CHECK(fabs(b0 - intercept) < sd + 1e-2);
+        TEST_CHECK(fabs(b1 - slope) < 5.0 * sd);
+      }
+
+      for (j = 0; j < n; j++)
+        x[j] = random() % 4 * TST_GetRandomDouble(-1000, 1000);
+
+      median = RGR_FindMedian(x, n);
+
+      for (j = c1 = c2 = c3 = 0; j < n; j++) {
+        if (x[j] < median)
+          c1++;
+        if (x[j] > median)
+          c3++;
+        else
+          c2++;
+      }
+
+      TEST_CHECK(c1 + c2 >= c3 && c1 <= c2 + c3);
+
+      xrange = TST_GetRandomDouble(1e-6, pow(10.0, random() % 10));
+      yrange = random() % 3 * TST_GetRandomDouble(0.0, pow(10.0, random() % 10));
+      wrange = random() % 3 * TST_GetRandomDouble(0.0, pow(10.0, random() % 10));
+      x2range = random() % 3 * TST_GetRandomDouble(0.0, pow(10.0, random() % 10));
+      m = random() % n;
+
+      for (j = 0; j < n; j++) {
+        x[j] = (j ? x[j - 1] : 0.0) + TST_GetRandomDouble(1e-6, xrange);
+        y[j] = TST_GetRandomDouble(-yrange, yrange);
+        w[j] = 1.0 + TST_GetRandomDouble(0.0, wrange);
+        x2[j] = TST_GetRandomDouble(-x2range, x2range);
+      }
+
+      RGR_WeightedRegression(x, y, w, n, &b0, &b1, &s2, &sb0, &sb1);
+
+      if (RGR_FindBestRegression(x + m, y + m, w, n - m, m, 3, &b0, &b1, &s2, &sb0, &sb1,
+                                 &best_start, &runs, &dof))
+        ;
+      if (RGR_MultipleRegress(x, x2, y, n, &b2))
+        ;
+      if (RGR_FindBestRobustRegression(x, y, n, 1e-8, &b0, &b1, &runs, &best_start))
+        ;
+    }
+  }
+}
diff --git a/chrony_3_3/test/unit/smooth.c b/chrony_3_3/test/unit/smooth.c
new file mode 100644
index 0000000..998a4d1
--- /dev/null
+++ b/chrony_3_3/test/unit/smooth.c
@@ -0,0 +1,63 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+ */
+
+#include <smooth.c>
+#include "test.h"
+
+void
+test_unit(void)
+{
+  int i, j;
+  struct timespec ts;
+  double offset, freq, wander;
+  char conf[] = "smoothtime 300 0.01";
+
+  CNF_Initialise(0, 0);
+  CNF_ParseLine(NULL, 1, conf);
+
+  LCL_Initialise();
+  SMT_Initialise();
+  locked = 0;
+
+  for (i = 0; i < 500; i++) {
+    UTI_ZeroTimespec(&ts);
+    SMT_Reset(&ts);
+
+    DEBUG_LOG("iteration %d", i);
+
+    offset = (random() % 1000000 - 500000) / 1.0e6;
+    freq = (random() % 1000000 - 500000) / 1.0e9;
+    update_smoothing(&ts, offset, freq);
+
+    for (j = 0; j < 10000; j++) {
+      update_smoothing(&ts, 0.0, 0.0);
+      UTI_AddDoubleToTimespec(&ts, 16.0, &ts);
+      get_smoothing(&ts, &offset, &freq, &wander);
+    }
+
+    TEST_CHECK(fabs(offset) < 1e-12);
+    TEST_CHECK(fabs(freq) < 1e-12);
+    TEST_CHECK(fabs(wander) < 1e-12);
+  }
+
+  SMT_Finalise();
+  LCL_Finalise();
+  CNF_Finalise();
+}
diff --git a/chrony_3_3/test/unit/sources.c b/chrony_3_3/test/unit/sources.c
new file mode 100644
index 0000000..341e22e
--- /dev/null
+++ b/chrony_3_3/test/unit/sources.c
@@ -0,0 +1,139 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+ */
+
+#include <sources.c>
+#include "test.h"
+
+void
+test_unit(void)
+{
+  SRC_Instance srcs[16];
+  RPT_SourceReport report;
+  IPAddr addr;
+  int i, j, k, l, samples, sel_options;
+  double offset, delay, disp;
+  struct timespec ts;
+
+  CNF_Initialise(0, 0);
+  LCL_Initialise();
+  TST_RegisterDummyDrivers();
+  SCH_Initialise();
+  SRC_Initialise();
+  REF_Initialise();
+
+  REF_SetMode(REF_ModeIgnore);
+
+  for (i = 0; i < 1000; i++) {
+    DEBUG_LOG("iteration %d", i);
+
+    for (j = 0; j < sizeof (srcs) / sizeof (srcs[0]); j++) {
+      TEST_CHECK(n_sources == j);
+
+      TST_GetRandomAddress(&addr, IPADDR_UNSPEC, -1);
+
+      sel_options = i & random() & (SRC_SELECT_NOSELECT | SRC_SELECT_PREFER |
+                                    SRC_SELECT_TRUST | SRC_SELECT_REQUIRE);
+
+      DEBUG_LOG("added source %d options %d", j, sel_options);
+      srcs[j] = SRC_CreateNewInstance(UTI_IPToRefid(&addr), SRC_NTP, sel_options, &addr,
+                                      SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES,
+                                      0.0, 1.0);
+      SRC_UpdateReachability(srcs[j], 1);
+
+      samples = (i + j) % 5 + 3;
+
+      offset = TST_GetRandomDouble(-1.0, 1.0);
+
+      for (k = 0; k < samples; k++) {
+        SCH_GetLastEventTime(&ts, NULL, NULL);
+        UTI_AddDoubleToTimespec(&ts, TST_GetRandomDouble(k - samples, k - samples + 1), &ts);
+
+        offset += TST_GetRandomDouble(-1.0e-2, 1.0e-2);
+        delay = TST_GetRandomDouble(1.0e-6, 1.0e-1);
+        disp = TST_GetRandomDouble(1.0e-6, 1.0e-1);
+
+        DEBUG_LOG("source %d sample %d offset %f delay %f disp %f", j, k,
+                  offset, delay, disp);
+
+        SRC_AccumulateSample(srcs[j], &ts, offset, delay, disp, delay, disp,
+                             1, LEAP_Normal);
+      }
+
+      for (k = 0; k <= j; k++) {
+        int passed = 0, trusted = 0, trusted_passed = 0, required = 0, required_passed = 0;
+        double trusted_lo = DBL_MAX, trusted_hi = DBL_MIN;
+        double passed_lo = DBL_MAX, passed_hi = DBL_MIN;
+
+        SRC_SelectSource(srcs[k]);
+        DEBUG_LOG("source %d status %d", k, sources[k]->status);
+
+        for (l = 0; l <= j; l++) {
+          TEST_CHECK(sources[l]->status > SRC_OK && sources[l]->status <= SRC_SELECTED);
+          if (sources[l]->sel_options & SRC_SELECT_NOSELECT) {
+            TEST_CHECK(sources[l]->status == SRC_UNSELECTABLE);
+          } else if (sources[l]->status != SRC_BAD_DISTANCE) {
+            if (sources[l]->status >= SRC_NONPREFERRED) {
+              passed++;
+              if (passed_lo > sources[l]->sel_info.lo_limit)
+                passed_lo = sources[l]->sel_info.lo_limit;
+              if (passed_hi < sources[l]->sel_info.hi_limit)
+                passed_hi = sources[l]->sel_info.hi_limit;
+            }
+            if (sources[l]->sel_options & SRC_SELECT_TRUST) {
+              trusted++;
+              if (trusted_lo > sources[l]->sel_info.lo_limit)
+                trusted_lo = sources[l]->sel_info.lo_limit;
+              if (trusted_hi < sources[l]->sel_info.hi_limit)
+                trusted_hi = sources[l]->sel_info.hi_limit;
+              if (sources[l]->status >= SRC_NONPREFERRED)
+                trusted_passed++;
+            }
+            if (sources[l]->sel_options & SRC_SELECT_REQUIRE) {
+              required++;
+              if (sources[l]->status >= SRC_NONPREFERRED)
+                required_passed++;
+            }
+            if (sources[l]->sel_options & SRC_SELECT_PREFER)
+              TEST_CHECK(sources[l]->status != SRC_NONPREFERRED);
+          }
+        }
+
+        DEBUG_LOG("sources %d passed %d trusted %d/%d required %d/%d", j, passed,
+                  trusted_passed, trusted, required_passed, required);
+
+        TEST_CHECK(!trusted || !passed || (passed_lo >= trusted_lo && passed_hi <= trusted_hi));
+        TEST_CHECK(!passed || trusted != 1 || (trusted == 1 && trusted_passed == 1));
+        TEST_CHECK(!passed || !required || required_passed > 0);
+      }
+    }
+
+    for (j = 0; j < sizeof (srcs) / sizeof (srcs[0]); j++) {
+      SRC_ReportSource(j, &report, &ts);
+      SRC_DestroyInstance(srcs[j]);
+    }
+  }
+
+  REF_Finalise();
+  SRC_Finalise();
+  SCH_Finalise();
+  LCL_Finalise();
+  CNF_Finalise();
+  HSH_Finalise();
+}
diff --git a/chrony_3_3/test/unit/test.c b/chrony_3_3/test/unit/test.c
new file mode 100644
index 0000000..67f7678
--- /dev/null
+++ b/chrony_3_3/test/unit/test.c
@@ -0,0 +1,169 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+ */
+
+#include <config.h>
+#include <sysincl.h>
+#include <logging.h>
+#include <localp.h>
+
+#include "test.h"
+
+void
+TST_Fail(int line)
+{
+  printf("FAIL (on line %d)\n", line);
+  exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+  char *test_name, *s;
+  int i, seed = 0;
+  struct timeval tv;
+
+  test_name = argv[0];
+  s = strrchr(test_name, '.');
+  if (s)
+    *s = '\0';
+  s = strrchr(test_name, '/');
+  if (s)
+    test_name = s + 1;
+
+  for (i = 1; i < argc; i++) {
+    if (!strcmp(argv[i], "-d")) {
+      LOG_SetDebugLevel(2);
+    } else if (!strcmp(argv[i], "-s") && i + 1 < argc) {
+      seed = atoi(argv[++i]);
+    } else {
+      fprintf(stderr, "Unknown option\n");
+      exit(1);
+    }
+  }
+
+  gettimeofday(&tv, NULL);
+  srandom(seed ? seed : tv.tv_sec ^ (tv.tv_usec << 10));
+
+  printf("Testing %-30s ", test_name);
+  fflush(stdout);
+
+  LOG_Initialise();
+
+  test_unit();
+
+  LOG_Finalise();
+
+  printf("PASS\n");
+
+  return 0;
+}
+
+double
+TST_GetRandomDouble(double min, double max)
+{
+  return min + (double)random() / RAND_MAX * (max - min);
+}
+
+void
+TST_GetRandomAddress(IPAddr *ip, int family, int bits)
+{
+  if (family != IPADDR_INET4 && family != IPADDR_INET6)
+    family = random() % 2 ? IPADDR_INET4 : IPADDR_INET6;
+
+  ip->family = family;
+
+  if (family == IPADDR_INET4) {
+    if (bits < 0)
+      bits = 32;
+    assert(bits <= 32);
+
+    if (bits > 16)
+      ip->addr.in4 = (uint32_t)random() % (1U << (bits - 16)) << 16 |
+                     (uint32_t)random() % (1U << 16);
+    else
+      ip->addr.in4 = (uint32_t)random() % (1U << bits);
+  } else {
+    int i, b;
+
+    if (bits < 0)
+      bits = 128;
+    assert(bits <= 128);
+
+    for (i = 0, b = 120; i < 16; i++, b -= 8) {
+      if (b >= bits) {
+        ip->addr.in6[i] = 0;
+      } else {
+        ip->addr.in6[i] = random() % (1U << MIN(bits - b, 8));
+      }
+    }
+  }
+}
+
+void
+TST_SwapAddressBit(IPAddr *ip, unsigned int b)
+{
+  if (ip->family == IPADDR_INET4) {
+    assert(b < 32);
+    ip->addr.in4 ^= 1U << (31 - b);
+  } else if (ip->family == IPADDR_INET6) {
+    assert(b < 128);
+    ip->addr.in6[b / 8] ^= 1U << (7 - b % 8);
+  } else {
+    assert(0);
+  }
+}
+
+static double
+read_frequency(void)
+{
+  return 0.0;
+}
+
+static double
+set_frequency(double freq_ppm)
+{
+  return 0.0;
+}
+
+static void
+accrue_offset(double offset, double corr_rate)
+{
+}
+
+static int
+apply_step_offset(double offset)
+{
+  return 0;
+}
+
+static void
+offset_convert(struct timespec *raw, double *corr, double *err)
+{
+  *corr = 0.0;
+  if (err)
+    *err = 0.0;
+}
+
+void
+TST_RegisterDummyDrivers(void)
+{
+  lcl_RegisterSystemDrivers(read_frequency, set_frequency, accrue_offset,
+                            apply_step_offset, offset_convert, NULL, NULL);
+}
diff --git a/chrony_3_3/test/unit/test.h b/chrony_3_3/test/unit/test.h
new file mode 100644
index 0000000..d96f3af
--- /dev/null
+++ b/chrony_3_3/test/unit/test.h
@@ -0,0 +1,43 @@
+/*
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  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.
+ * 
+ **********************************************************************
+ */
+
+#ifndef GOT_TEST_H
+#define GOT_TEST_H
+
+#include <addressing.h>
+
+extern void test_unit(void);
+
+#define TEST_CHECK(expr) \
+  do { \
+    if (!(expr)) { \
+      TST_Fail(__LINE__); \
+      exit(1); \
+    } \
+  } while (0)
+
+extern void TST_Fail(int line);
+
+extern double TST_GetRandomDouble(double min, double max);
+extern void TST_GetRandomAddress(IPAddr *ip, int family, int bits);
+extern void TST_SwapAddressBit(IPAddr *ip, unsigned int b);
+extern void TST_RegisterDummyDrivers(void);
+
+#endif
diff --git a/chrony_3_3/test/unit/util.c b/chrony_3_3/test/unit/util.c
new file mode 100644
index 0000000..5f1a653
--- /dev/null
+++ b/chrony_3_3/test/unit/util.c
@@ -0,0 +1,199 @@
+#include <util.c>
+#include "test.h"
+
+void test_unit(void) {
+  NTP_int64 ntp_ts, ntp_fuzz;
+  struct timespec ts, ts2;
+  struct timeval tv;
+  struct sockaddr_un sun;
+  double x, y;
+  Float f;
+  int i, j, c;
+  char buf[16], *s;
+
+  for (i = -31; i < 31; i++) {
+    x = pow(2.0, i);
+    y = UTI_Log2ToDouble(i);
+    TEST_CHECK(y / x > 0.99999 && y / x < 1.00001);
+  }
+
+  for (i = -89; i < 63; i++) {
+    x = pow(2.0, i);
+    y = UTI_FloatNetworkToHost(UTI_FloatHostToNetwork(x));
+    TEST_CHECK(y / x > 0.99999 && y / x < 1.00001);
+  }
+
+  for (i = 0; i < 100000; i++) {
+    x = TST_GetRandomDouble(-1000.0, 1000.0);
+    y = UTI_FloatNetworkToHost(UTI_FloatHostToNetwork(x));
+    TEST_CHECK(y / x > 0.99999 && y / x < 1.00001);
+
+    UTI_GetRandomBytes(&f, sizeof (f));
+    x = UTI_FloatNetworkToHost(f);
+    TEST_CHECK(x > 0.0 || x <= 0.0);
+  }
+
+  TEST_CHECK(UTI_DoubleToNtp32(1.0) == htonl(65536));
+  TEST_CHECK(UTI_DoubleToNtp32(0.0) == htonl(0));
+  TEST_CHECK(UTI_DoubleToNtp32(1.0 / (65536.0)) == htonl(1));
+  TEST_CHECK(UTI_DoubleToNtp32(1.000001 / (65536.0)) == htonl(2));
+  TEST_CHECK(UTI_DoubleToNtp32(1.000001) == htonl(65537));
+  TEST_CHECK(UTI_DoubleToNtp32(1000000) == htonl(0xffffffff));
+  TEST_CHECK(UTI_DoubleToNtp32(-1.0) == htonl(0));
+
+  UTI_DoubleToTimeval(0.4e-6, &tv);
+  TEST_CHECK(tv.tv_sec == 0);
+  TEST_CHECK(tv.tv_usec == 0);
+  UTI_DoubleToTimeval(-0.4e-6, &tv);
+  TEST_CHECK(tv.tv_sec == 0);
+  TEST_CHECK(tv.tv_usec == 0);
+  UTI_DoubleToTimeval(0.5e-6, &tv);
+  TEST_CHECK(tv.tv_sec == 0);
+  TEST_CHECK(tv.tv_usec == 1);
+  UTI_DoubleToTimeval(-0.5e-6, &tv);
+  TEST_CHECK(tv.tv_sec == -1);
+  TEST_CHECK(tv.tv_usec == 999999);
+
+  UTI_DoubleToTimespec(0.9e-9, &ts);
+  TEST_CHECK(ts.tv_sec == 0);
+  TEST_CHECK(ts.tv_nsec == 0);
+  UTI_DoubleToTimespec(1.0e-9, &ts);
+  TEST_CHECK(ts.tv_sec == 0);
+  TEST_CHECK(ts.tv_nsec == 1);
+  UTI_DoubleToTimespec(-0.9e-9, &ts);
+  TEST_CHECK(ts.tv_sec == 0);
+  TEST_CHECK(ts.tv_nsec == 0);
+  UTI_DoubleToTimespec(-1.0e-9, &ts);
+  TEST_CHECK(ts.tv_sec == -1);
+  TEST_CHECK(ts.tv_nsec == 999999999);
+
+  ntp_ts.hi = htonl(JAN_1970);
+  ntp_ts.lo = 0xffffffff;
+  UTI_Ntp64ToTimespec(&ntp_ts, &ts);
+  TEST_CHECK(ts.tv_sec == 0);
+  TEST_CHECK(ts.tv_nsec == 999999999);
+
+  UTI_AddDoubleToTimespec(&ts, 1e-9, &ts);
+  TEST_CHECK(ts.tv_sec == 1);
+  TEST_CHECK(ts.tv_nsec == 0);
+
+  ntp_fuzz.hi = 0;
+  ntp_fuzz.lo = htonl(0xff1234ff);
+
+  UTI_TimespecToNtp64(&ts, &ntp_ts, &ntp_fuzz);
+  TEST_CHECK(ntp_ts.hi == htonl(JAN_1970 + 1));
+  TEST_CHECK(ntp_ts.lo == ntp_fuzz.lo);
+
+  ts.tv_sec = ts.tv_nsec = 0;
+  UTI_TimespecToNtp64(&ts, &ntp_ts, &ntp_fuzz);
+  TEST_CHECK(ntp_ts.hi == 0);
+  TEST_CHECK(ntp_ts.lo == 0);
+
+  TEST_CHECK(UTI_IsZeroTimespec(&ts));
+  TEST_CHECK(UTI_IsZeroNtp64(&ntp_ts));
+
+  ts.tv_sec = 1;
+  ntp_ts.hi = htonl(1);
+
+  TEST_CHECK(!UTI_IsZeroTimespec(&ts));
+  TEST_CHECK(!UTI_IsZeroNtp64(&ntp_ts));
+
+  ts.tv_sec = 0;
+  ntp_ts.hi = 0;
+  ts.tv_nsec = 1;
+  ntp_ts.lo = htonl(1);
+
+  TEST_CHECK(!UTI_IsZeroTimespec(&ts));
+  TEST_CHECK(!UTI_IsZeroNtp64(&ntp_ts));
+
+  ntp_ts.hi = 0;
+  ntp_ts.lo = 0;
+
+  UTI_Ntp64ToTimespec(&ntp_ts, &ts);
+  TEST_CHECK(UTI_IsZeroTimespec(&ts));
+  UTI_TimespecToNtp64(&ts, &ntp_ts, NULL);
+  TEST_CHECK(UTI_IsZeroNtp64(&ntp_ts));
+
+  ntp_fuzz.hi = htonl(1);
+  ntp_fuzz.lo = htonl(3);
+  ntp_ts.hi = htonl(1);
+  ntp_ts.lo = htonl(2);
+
+  TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_ts) == 0);
+  TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_fuzz) < 0);
+  TEST_CHECK(UTI_CompareNtp64(&ntp_fuzz, &ntp_ts) > 0);
+
+  ntp_ts.hi = htonl(0x80000002);
+  ntp_ts.lo = htonl(2);
+
+  TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_ts) == 0);
+  TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_fuzz) < 0);
+  TEST_CHECK(UTI_CompareNtp64(&ntp_fuzz, &ntp_ts) > 0);
+
+  ntp_fuzz.hi = htonl(0x90000001);
+
+  TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_ts) == 0);
+  TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_fuzz) < 0);
+  TEST_CHECK(UTI_CompareNtp64(&ntp_fuzz, &ntp_ts) > 0);
+
+  TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, &ntp_ts, NULL, NULL));
+  TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, NULL, &ntp_ts, NULL));
+  TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, NULL, NULL, &ntp_ts));
+  TEST_CHECK(!UTI_IsEqualAnyNtp64(&ntp_ts, &ntp_fuzz, &ntp_fuzz, &ntp_fuzz));
+
+  ts.tv_sec = 1;
+  ts.tv_nsec = 2;
+  ts2.tv_sec = 1;
+  ts2.tv_nsec = 3;
+
+  TEST_CHECK(UTI_CompareTimespecs(&ts, &ts) == 0);
+  TEST_CHECK(UTI_CompareTimespecs(&ts, &ts2) < 0);
+  TEST_CHECK(UTI_CompareTimespecs(&ts2, &ts) > 0);
+
+  ts2.tv_sec = 2;
+
+  TEST_CHECK(UTI_CompareTimespecs(&ts, &ts) == 0);
+  TEST_CHECK(UTI_CompareTimespecs(&ts, &ts2) < 0);
+  TEST_CHECK(UTI_CompareTimespecs(&ts2, &ts) > 0);
+
+  for (i = -32; i <= 32; i++) {
+    for (j = c = 0; j < 1000; j++) {
+      UTI_GetNtp64Fuzz(&ntp_fuzz, i);
+      if (i <= 0)
+        TEST_CHECK(ntp_fuzz.hi == 0);
+      if (i < 0)
+        TEST_CHECK(ntohl(ntp_fuzz.lo) < 1U << (32 + i));
+      else if (i < 32)
+        TEST_CHECK(ntohl(ntp_fuzz.hi) < 1U << i);
+      if (ntohl(ntp_fuzz.lo) >= 1U << (31 + CLAMP(-31, i, 0)))
+        c++;
+    }
+
+    if (i == -32)
+      TEST_CHECK(c == 0);
+    else
+      TEST_CHECK(c > 400 && c < 600);
+  }
+
+  for (i = c = 0; i < 100000; i++) {
+    j = random() % (sizeof (buf) + 1);
+    UTI_GetRandomBytes(buf, j);
+    if (j && buf[j - 1] % 2)
+      c++;
+  }
+  TEST_CHECK(c > 46000 && c < 48000);
+
+  for (i = 1; i < 2 * BUFFER_LENGTH; i++) {
+    sun.sun_family = AF_UNIX;
+    for (j = 0; j + 1 < i && j + 1 < sizeof (sun.sun_path); j++)
+      sun.sun_path[j] = 'A' + j % 26;
+    sun.sun_path[j] = '\0';
+    s = UTI_SockaddrToString((struct sockaddr *)&sun);
+    if (i <= BUFFER_LENGTH) {
+      TEST_CHECK(!strcmp(s, sun.sun_path));
+    } else {
+      TEST_CHECK(!strncmp(s, sun.sun_path, BUFFER_LENGTH - 2));
+      TEST_CHECK(s[BUFFER_LENGTH - 2] == '>');
+    }
+  }
+}
diff --git a/chrony_3_3/util.c b/chrony_3_3/util.c
new file mode 100644
index 0000000..4b3e455
--- /dev/null
+++ b/chrony_3_3/util.c
@@ -0,0 +1,1255 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Richard P. Curnow  1997-2003
+ * Copyright (C) Miroslav Lichvar  2009, 2012-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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Various utility functions
+  */
+
+#include "config.h"
+
+#include "sysincl.h"
+
+#include "logging.h"
+#include "memory.h"
+#include "util.h"
+#include "hash.h"
+
+#define NSEC_PER_SEC 1000000000
+
+/* ================================================== */
+
+void
+UTI_ZeroTimespec(struct timespec *ts)
+{
+  ts->tv_sec = 0;
+  ts->tv_nsec = 0;
+}
+
+/* ================================================== */
+
+int
+UTI_IsZeroTimespec(struct timespec *ts)
+{
+  return !ts->tv_sec && !ts->tv_nsec;
+}
+
+/* ================================================== */
+
+void
+UTI_TimevalToTimespec(struct timeval *tv, struct timespec *ts)
+{
+  ts->tv_sec = tv->tv_sec;
+  ts->tv_nsec = 1000 * tv->tv_usec;
+}
+
+/* ================================================== */
+
+void
+UTI_TimespecToTimeval(struct timespec *ts, struct timeval *tv)
+{
+  tv->tv_sec = ts->tv_sec;
+  tv->tv_usec = ts->tv_nsec / 1000;
+}
+
+/* ================================================== */
+
+double
+UTI_TimespecToDouble(struct timespec *ts)
+{
+  return ts->tv_sec + 1.0e-9 * ts->tv_nsec;
+}
+
+/* ================================================== */
+
+void
+UTI_DoubleToTimespec(double d, struct timespec *ts)
+{
+  ts->tv_sec = d;
+  ts->tv_nsec = 1.0e9 * (d - ts->tv_sec);
+  UTI_NormaliseTimespec(ts);
+}
+
+/* ================================================== */
+
+void
+UTI_NormaliseTimespec(struct timespec *ts)
+{
+  if (ts->tv_nsec >= NSEC_PER_SEC || ts->tv_nsec < 0) {
+    ts->tv_sec += ts->tv_nsec / NSEC_PER_SEC;
+    ts->tv_nsec = ts->tv_nsec % NSEC_PER_SEC;
+
+    /* If seconds are negative nanoseconds would end up negative too */
+    if (ts->tv_nsec < 0) {
+      ts->tv_sec--;
+      ts->tv_nsec += NSEC_PER_SEC;
+    }
+  }
+}
+
+/* ================================================== */
+
+double
+UTI_TimevalToDouble(struct timeval *tv)
+{
+  return tv->tv_sec + 1.0e-6 * tv->tv_usec;
+}
+
+/* ================================================== */
+
+void
+UTI_DoubleToTimeval(double a, struct timeval *b)
+{
+  double frac_part;
+
+  b->tv_sec = a;
+  frac_part = 1.0e6 * (a - b->tv_sec);
+  b->tv_usec = frac_part > 0 ? frac_part + 0.5 : frac_part - 0.5;
+  UTI_NormaliseTimeval(b);
+}
+
+/* ================================================== */
+
+void
+UTI_NormaliseTimeval(struct timeval *x)
+{
+  /* Reduce tv_usec to within +-1000000 of zero. JGH */
+  if ((x->tv_usec >= 1000000) || (x->tv_usec <= -1000000)) {
+    x->tv_sec += x->tv_usec/1000000;
+    x->tv_usec = x->tv_usec%1000000;
+  }
+
+  /* Make tv_usec positive. JGH */
+   if (x->tv_usec < 0) {
+    --x->tv_sec;
+    x->tv_usec += 1000000;
+ }
+
+}
+
+/* ================================================== */
+
+int
+UTI_CompareTimespecs(struct timespec *a, struct timespec *b)
+{
+  if (a->tv_sec < b->tv_sec)
+    return -1;
+  if (a->tv_sec > b->tv_sec)
+    return 1;
+  if (a->tv_nsec < b->tv_nsec)
+    return -1;
+  if (a->tv_nsec > b->tv_nsec)
+    return 1;
+  return 0;
+}
+
+/* ================================================== */
+
+void
+UTI_DiffTimespecs(struct timespec *result, struct timespec *a, struct timespec *b)
+{
+  result->tv_sec = a->tv_sec - b->tv_sec;
+  result->tv_nsec = a->tv_nsec - b->tv_nsec;
+  UTI_NormaliseTimespec(result);
+}
+
+/* ================================================== */
+
+/* Calculate result = a - b and return as a double */
+double
+UTI_DiffTimespecsToDouble(struct timespec *a, struct timespec *b)
+{
+  return ((double)a->tv_sec - (double)b->tv_sec) + 1.0e-9 * (a->tv_nsec - b->tv_nsec);
+}
+
+/* ================================================== */
+
+void
+UTI_AddDoubleToTimespec(struct timespec *start, double increment, struct timespec *end)
+{
+  time_t int_part;
+
+  int_part = increment;
+  end->tv_sec = start->tv_sec + int_part;
+  end->tv_nsec = start->tv_nsec + 1.0e9 * (increment - int_part);
+  UTI_NormaliseTimespec(end);
+}
+
+/* ================================================== */
+
+/* Calculate the average and difference (as a double) of two timespecs */
+void
+UTI_AverageDiffTimespecs(struct timespec *earlier, struct timespec *later,
+                         struct timespec *average, double *diff)
+{
+  *diff = UTI_DiffTimespecsToDouble(later, earlier);
+  UTI_AddDoubleToTimespec(earlier, *diff / 2.0, average);
+}
+
+/* ================================================== */
+
+void
+UTI_AddDiffToTimespec(struct timespec *a, struct timespec *b,
+                      struct timespec *c, struct timespec *result)
+{
+  double diff;
+
+  diff = UTI_DiffTimespecsToDouble(a, b);
+  UTI_AddDoubleToTimespec(c, diff, result);
+}
+
+/* ================================================== */
+
+#define POOL_ENTRIES 16
+#define BUFFER_LENGTH 64
+static char buffer_pool[POOL_ENTRIES][BUFFER_LENGTH];
+static int  pool_ptr = 0;
+
+#define NEXT_BUFFER (buffer_pool[pool_ptr = ((pool_ptr + 1) % POOL_ENTRIES)])
+
+/* ================================================== */
+/* Convert a timespec into a temporary string, largely for diagnostic display */
+
+char *
+UTI_TimespecToString(struct timespec *ts)
+{
+  char *result;
+
+  result = NEXT_BUFFER;
+#ifdef HAVE_LONG_TIME_T
+  snprintf(result, BUFFER_LENGTH, "%"PRId64".%09lu",
+           (int64_t)ts->tv_sec, (unsigned long)ts->tv_nsec);
+#else
+  snprintf(result, BUFFER_LENGTH, "%ld.%09lu",
+           (long)ts->tv_sec, (unsigned long)ts->tv_nsec);
+#endif
+  return result;
+}
+
+/* ================================================== */
+/* Convert an NTP timestamp into a temporary string, largely
+   for diagnostic display */
+
+char *
+UTI_Ntp64ToString(NTP_int64 *ntp_ts)
+{
+  struct timespec ts;
+  UTI_Ntp64ToTimespec(ntp_ts, &ts);
+  return UTI_TimespecToString(&ts);
+}
+
+/* ================================================== */
+
+char *
+UTI_RefidToString(uint32_t ref_id)
+{
+  unsigned int i, j, c;
+  char *result;
+
+  result = NEXT_BUFFER;
+
+  for (i = j = 0; i < 4 && i < BUFFER_LENGTH - 1; i++) {
+    c = (ref_id >> (24 - i * 8)) & 0xff;
+    if (isprint(c))
+      result[j++] = c;
+  }
+
+  result[j] = '\0';
+
+  return result;
+}
+
+/* ================================================== */
+
+char *
+UTI_IPToString(IPAddr *addr)
+{
+  unsigned long a, b, c, d, ip;
+  uint8_t *ip6;
+  char *result;
+
+  result = NEXT_BUFFER;
+  switch (addr->family) {
+    case IPADDR_UNSPEC:
+      snprintf(result, BUFFER_LENGTH, "[UNSPEC]");
+      break;
+    case IPADDR_INET4:
+      ip = addr->addr.in4;
+      a = (ip>>24) & 0xff;
+      b = (ip>>16) & 0xff;
+      c = (ip>> 8) & 0xff;
+      d = (ip>> 0) & 0xff;
+      snprintf(result, BUFFER_LENGTH, "%ld.%ld.%ld.%ld", a, b, c, d);
+      break;
+    case IPADDR_INET6:
+      ip6 = addr->addr.in6;
+#ifdef FEAT_IPV6
+      inet_ntop(AF_INET6, ip6, result, BUFFER_LENGTH);
+#else
+      snprintf(result, BUFFER_LENGTH, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+               ip6[0], ip6[1], ip6[2], ip6[3], ip6[4], ip6[5], ip6[6], ip6[7],
+               ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]);
+#endif
+      break;
+    default:
+      snprintf(result, BUFFER_LENGTH, "[UNKNOWN]");
+  }
+  return result;
+}
+
+/* ================================================== */
+
+int
+UTI_StringToIP(const char *addr, IPAddr *ip)
+{
+#ifdef FEAT_IPV6
+  struct in_addr in4;
+  struct in6_addr in6;
+
+  if (inet_pton(AF_INET, addr, &in4) > 0) {
+    ip->family = IPADDR_INET4;
+    ip->_pad = 0;
+    ip->addr.in4 = ntohl(in4.s_addr);
+    return 1;
+  }
+
+  if (inet_pton(AF_INET6, addr, &in6) > 0) {
+    ip->family = IPADDR_INET6;
+    ip->_pad = 0;
+    memcpy(ip->addr.in6, in6.s6_addr, sizeof (ip->addr.in6));
+    return 1;
+  }
+#else
+  unsigned long a, b, c, d, n;
+
+  n = sscanf(addr, "%lu.%lu.%lu.%lu", &a, &b, &c, &d);
+  if (n == 4) {
+    ip->family = IPADDR_INET4;
+    ip->_pad = 0;
+    ip->addr.in4 = ((a & 0xff) << 24) | ((b & 0xff) << 16) | 
+                   ((c & 0xff) << 8) | (d & 0xff);
+    return 1;
+  }
+#endif
+
+  return 0;
+}
+
+/* ================================================== */
+
+uint32_t
+UTI_IPToRefid(IPAddr *ip)
+{
+  static int MD5_hash = -1;
+  unsigned char buf[16];
+
+  switch (ip->family) {
+    case IPADDR_INET4:
+      return ip->addr.in4;
+    case IPADDR_INET6:
+      if (MD5_hash < 0)
+        MD5_hash = HSH_GetHashId("MD5");
+
+      if (MD5_hash < 0 ||
+          HSH_Hash(MD5_hash, (const unsigned char *)ip->addr.in6, sizeof (ip->addr.in6),
+                   NULL, 0, buf, sizeof (buf)) != sizeof (buf))
+        LOG_FATAL("Could not get MD5");
+
+      return (uint32_t)buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
+  }
+  return 0;
+}
+
+/* ================================================== */
+
+uint32_t
+UTI_IPToHash(IPAddr *ip)
+{
+  static uint32_t seed = 0;
+  unsigned char *addr;
+  unsigned int i, len;
+  uint32_t hash;
+
+  switch (ip->family) {
+    case IPADDR_INET4:
+      addr = (unsigned char *)&ip->addr.in4;
+      len = sizeof (ip->addr.in4);
+      break;
+    case IPADDR_INET6:
+      addr = ip->addr.in6;
+      len = sizeof (ip->addr.in6);
+      break;
+    default:
+      return 0;
+  }
+
+  /* Include a random seed in the hash to randomize collisions
+     and order of addresses in hash tables */
+  while (!seed)
+    UTI_GetRandomBytes(&seed, sizeof (seed));
+
+  for (i = 0, hash = seed; i < len; i++)
+    hash = 71 * hash + addr[i];
+
+  return hash + seed;
+}
+
+/* ================================================== */
+
+void
+UTI_IPHostToNetwork(IPAddr *src, IPAddr *dest)
+{
+  /* Don't send uninitialized bytes over network */
+  memset(dest, 0, sizeof (IPAddr));
+
+  dest->family = htons(src->family);
+
+  switch (src->family) {
+    case IPADDR_INET4:
+      dest->addr.in4 = htonl(src->addr.in4);
+      break;
+    case IPADDR_INET6:
+      memcpy(dest->addr.in6, src->addr.in6, sizeof (dest->addr.in6));
+      break;
+    default:
+      dest->family = htons(IPADDR_UNSPEC);
+  }
+}
+
+/* ================================================== */
+
+void
+UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest)
+{
+  dest->family = ntohs(src->family);
+  dest->_pad = 0;
+
+  switch (dest->family) {
+    case IPADDR_INET4:
+      dest->addr.in4 = ntohl(src->addr.in4);
+      break;
+    case IPADDR_INET6:
+      memcpy(dest->addr.in6, src->addr.in6, sizeof (dest->addr.in6));
+      break;
+    default:
+      dest->family = IPADDR_UNSPEC;
+  }
+}
+
+/* ================================================== */
+
+int
+UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask)
+{
+  int i, d;
+
+  if (a->family != b->family)
+    return a->family - b->family;
+
+  if (mask && mask->family != b->family)
+    mask = NULL;
+
+  switch (a->family) {
+    case IPADDR_UNSPEC:
+      return 0;
+    case IPADDR_INET4:
+      if (mask)
+        return (a->addr.in4 & mask->addr.in4) - (b->addr.in4 & mask->addr.in4);
+      else
+        return a->addr.in4 - b->addr.in4;
+    case IPADDR_INET6:
+      for (i = 0, d = 0; !d && i < 16; i++) {
+        if (mask)
+          d = (a->addr.in6[i] & mask->addr.in6[i]) -
+              (b->addr.in6[i] & mask->addr.in6[i]);
+        else
+          d = a->addr.in6[i] - b->addr.in6[i];
+      }
+      return d;
+  }
+  return 0;
+}
+
+/* ================================================== */
+
+void
+UTI_SockaddrToIPAndPort(struct sockaddr *sa, IPAddr *ip, unsigned short *port)
+{
+  switch (sa->sa_family) {
+    case AF_INET:
+      ip->family = IPADDR_INET4;
+      ip->addr.in4 = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
+      *port = ntohs(((struct sockaddr_in *)sa)->sin_port);
+      break;
+#ifdef FEAT_IPV6
+    case AF_INET6:
+      ip->family = IPADDR_INET6;
+      memcpy(ip->addr.in6, ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr,
+             sizeof (ip->addr.in6));
+      *port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+      break;
+#endif
+    default:
+      ip->family = IPADDR_UNSPEC;
+      *port = 0;
+  }
+}
+
+/* ================================================== */
+
+int
+UTI_IPAndPortToSockaddr(IPAddr *ip, unsigned short port, struct sockaddr *sa)
+{
+  switch (ip->family) {
+    case IPADDR_INET4:
+      memset(sa, 0, sizeof (struct sockaddr_in));
+      sa->sa_family = AF_INET;
+      ((struct sockaddr_in *)sa)->sin_addr.s_addr = htonl(ip->addr.in4);
+      ((struct sockaddr_in *)sa)->sin_port = htons(port);
+#ifdef SIN6_LEN
+      ((struct sockaddr_in *)sa)->sin_len = sizeof (struct sockaddr_in);
+#endif
+      return sizeof (struct sockaddr_in);
+#ifdef FEAT_IPV6
+    case IPADDR_INET6:
+      memset(sa, 0, sizeof (struct sockaddr_in6));
+      sa->sa_family = AF_INET6;
+      memcpy(((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr, ip->addr.in6,
+             sizeof (ip->addr.in6));
+      ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
+#ifdef SIN6_LEN
+      ((struct sockaddr_in6 *)sa)->sin6_len = sizeof (struct sockaddr_in6);
+#endif
+      return sizeof (struct sockaddr_in6);
+#endif
+    default:
+      memset(sa, 0, sizeof (struct sockaddr));
+      sa->sa_family = AF_UNSPEC;
+      return 0;
+  }
+}
+
+/* ================================================== */
+
+char *UTI_SockaddrToString(struct sockaddr *sa)
+{
+  unsigned short port;
+  IPAddr ip;
+  char *result, *sun_path;
+
+  result = NEXT_BUFFER;
+
+  switch (sa->sa_family) {
+    case AF_INET:
+#ifdef AF_INET6
+    case AF_INET6:
+#endif
+      UTI_SockaddrToIPAndPort(sa, &ip, &port);
+      snprintf(result, BUFFER_LENGTH, "%s:%hu", UTI_IPToString(&ip), port);
+      break;
+    case AF_UNIX:
+      sun_path = ((struct sockaddr_un *)sa)->sun_path;
+      snprintf(result, BUFFER_LENGTH, "%.*s", BUFFER_LENGTH - 1, sun_path);
+      /* Indicate truncated path */
+      if (strlen(sun_path) >= BUFFER_LENGTH)
+        result[BUFFER_LENGTH - 2] = '>';
+      break;
+    default:
+      snprintf(result, BUFFER_LENGTH, "[UNKNOWN]");
+  }
+
+  return result;
+}
+
+/* ================================================== */
+
+const char *
+UTI_SockaddrFamilyToString(int family)
+{
+  switch (family) {
+    case AF_INET:
+      return "IPv4";
+#ifdef AF_INET6
+    case AF_INET6:
+      return "IPv6";
+#endif
+    case AF_UNIX:
+      return "Unix";
+    case AF_UNSPEC:
+      return "UNSPEC";
+    default:
+      return "?";
+  }
+}
+
+/* ================================================== */
+
+char *
+UTI_TimeToLogForm(time_t t)
+{
+  struct tm *stm;
+  char *result;
+
+  result = NEXT_BUFFER;
+
+  stm = gmtime(&t);
+
+  if (stm)
+    strftime(result, BUFFER_LENGTH, "%Y-%m-%d %H:%M:%S", stm);
+  else
+    snprintf(result, BUFFER_LENGTH, "INVALID    INVALID ");
+
+  return result;
+}
+
+/* ================================================== */
+
+void
+UTI_AdjustTimespec(struct timespec *old_ts, struct timespec *when, struct timespec *new_ts, double *delta_time, double dfreq, double doffset)
+{
+  double elapsed;
+
+  elapsed = UTI_DiffTimespecsToDouble(when, old_ts);
+  *delta_time = elapsed * dfreq - doffset;
+  UTI_AddDoubleToTimespec(old_ts, *delta_time, new_ts);
+}
+
+/* ================================================== */
+
+void
+UTI_GetNtp64Fuzz(NTP_int64 *ts, int precision)
+{
+  int start, bits;
+
+  assert(precision >= -32 && precision <= 32);
+  assert(sizeof (*ts) == 8);
+
+  start = sizeof (*ts) - (precision + 32 + 7) / 8;
+  ts->hi = ts->lo = 0;
+
+  UTI_GetRandomBytes((unsigned char *)ts + start, sizeof (*ts) - start);
+
+  bits = (precision + 32) % 8;
+  if (bits)
+    ((unsigned char *)ts)[start] %= 1U << bits;
+}
+
+/* ================================================== */
+
+double
+UTI_Ntp32ToDouble(NTP_int32 x)
+{
+  return (double) ntohl(x) / 65536.0;
+}
+
+/* ================================================== */
+
+#define MAX_NTP_INT32 (4294967295.0 / 65536.0)
+
+NTP_int32
+UTI_DoubleToNtp32(double x)
+{
+  NTP_int32 r;
+
+  if (x >= MAX_NTP_INT32) {
+    r = 0xffffffff;
+  } else if (x <= 0.0) {
+    r = 0;
+  } else {
+    x *= 65536.0;
+    r = x;
+
+    /* Round up */
+    if (r < x)
+      r++;
+  }
+
+  return htonl(r);
+}
+
+/* ================================================== */
+
+void
+UTI_ZeroNtp64(NTP_int64 *ts)
+{
+  ts->hi = ts->lo = htonl(0);
+}
+
+/* ================================================== */
+
+int
+UTI_IsZeroNtp64(NTP_int64 *ts)
+{
+  return !ts->hi && !ts->lo;
+}
+
+/* ================================================== */
+
+int
+UTI_CompareNtp64(NTP_int64 *a, NTP_int64 *b)
+{
+  int32_t diff;
+
+  if (a->hi == b->hi && a->lo == b->lo)
+    return 0;
+
+  diff = ntohl(a->hi) - ntohl(b->hi);
+
+  if (diff < 0)
+    return -1;
+  if (diff > 0)
+    return 1;
+
+  return ntohl(a->lo) < ntohl(b->lo) ? -1 : 1;
+}
+
+/* ================================================== */
+
+int
+UTI_IsEqualAnyNtp64(NTP_int64 *a, NTP_int64 *b1, NTP_int64 *b2, NTP_int64 *b3)
+{
+  if (b1 && a->lo == b1->lo && a->hi == b1->hi)
+    return 1;
+
+  if (b2 && a->lo == b2->lo && a->hi == b2->hi)
+    return 1;
+
+  if (b3 && a->lo == b3->lo && a->hi == b3->hi)
+    return 1;
+
+  return 0;
+}
+
+/* ================================================== */
+
+/* Seconds part of NTP timestamp correponding to the origin of the time_t format */
+#define JAN_1970 0x83aa7e80UL
+
+#define NSEC_PER_NTP64 4.294967296
+
+void
+UTI_TimespecToNtp64(struct timespec *src, NTP_int64 *dest, NTP_int64 *fuzz)
+{
+  uint32_t hi, lo, sec, nsec;
+
+  sec = (uint32_t)src->tv_sec;
+  nsec = (uint32_t)src->tv_nsec;
+
+  /* Recognize zero as a special case - it always signifies
+     an 'unknown' value */
+  if (!nsec && !sec) {
+    hi = lo = 0;
+  } else {
+    hi = htonl(sec + JAN_1970);
+    lo = htonl(NSEC_PER_NTP64 * nsec);
+
+    /* Add the fuzz */
+    if (fuzz) {
+      hi ^= fuzz->hi;
+      lo ^= fuzz->lo;
+    }
+  }
+
+  dest->hi = hi;
+  dest->lo = lo;
+}
+
+/* ================================================== */
+
+void
+UTI_Ntp64ToTimespec(NTP_int64 *src, struct timespec *dest)
+{
+  uint32_t ntp_sec, ntp_frac;
+
+  /* Zero is a special value */
+  if (UTI_IsZeroNtp64(src)) {
+    UTI_ZeroTimespec(dest);
+    return;
+  }
+
+  ntp_sec = ntohl(src->hi);
+  ntp_frac = ntohl(src->lo);
+
+#ifdef HAVE_LONG_TIME_T
+  dest->tv_sec = ntp_sec - (uint32_t)(NTP_ERA_SPLIT + JAN_1970) +
+                 (time_t)NTP_ERA_SPLIT;
+#else
+  dest->tv_sec = ntp_sec - JAN_1970;
+#endif
+
+  dest->tv_nsec = ntp_frac / NSEC_PER_NTP64;
+}
+
+/* ================================================== */
+
+/* Maximum offset between two sane times */
+#define MAX_OFFSET 4294967296.0
+
+/* Minimum allowed distance from maximum 32-bit time_t */
+#define MIN_ENDOFTIME_DISTANCE (365 * 24 * 3600)
+
+int
+UTI_IsTimeOffsetSane(struct timespec *ts, double offset)
+{
+  double t;
+
+  /* Handle nan correctly here */
+  if (!(offset > -MAX_OFFSET && offset < MAX_OFFSET))
+    return 0;
+
+  t = UTI_TimespecToDouble(ts) + offset;
+
+  /* Time before 1970 is not considered valid */
+  if (t < 0.0)
+    return 0;
+
+#ifdef HAVE_LONG_TIME_T
+  /* Check if it's in the interval to which NTP time is mapped */
+  if (t < (double)NTP_ERA_SPLIT || t > (double)(NTP_ERA_SPLIT + (1LL << 32)))
+    return 0;
+#else
+  /* Don't get too close to 32-bit time_t overflow */
+  if (t > (double)(0x7fffffff - MIN_ENDOFTIME_DISTANCE))
+    return 0;
+#endif
+
+  return 1;
+}
+
+/* ================================================== */
+
+double
+UTI_Log2ToDouble(int l)
+{
+  if (l >= 0) {
+    if (l > 31)
+      l = 31;
+    return (uint32_t)1 << l;
+  } else {
+    if (l < -31)
+      l = -31;
+    return 1.0 / ((uint32_t)1 << -l);
+  }
+}
+
+/* ================================================== */
+
+void
+UTI_TimespecNetworkToHost(Timespec *src, struct timespec *dest)
+{
+  uint32_t sec_low, nsec;
+#ifdef HAVE_LONG_TIME_T
+  uint32_t sec_high;
+#endif
+
+  sec_low = ntohl(src->tv_sec_low);
+#ifdef HAVE_LONG_TIME_T
+  sec_high = ntohl(src->tv_sec_high);
+  if (sec_high == TV_NOHIGHSEC)
+    sec_high = 0;
+
+  dest->tv_sec = (uint64_t)sec_high << 32 | sec_low;
+#else
+  dest->tv_sec = sec_low;
+#endif
+
+  nsec = ntohl(src->tv_nsec);
+  dest->tv_nsec = MIN(nsec, 999999999U);
+}
+
+/* ================================================== */
+
+void
+UTI_TimespecHostToNetwork(struct timespec *src, Timespec *dest)
+{
+  dest->tv_nsec = htonl(src->tv_nsec);
+#ifdef HAVE_LONG_TIME_T
+  dest->tv_sec_high = htonl((uint64_t)src->tv_sec >> 32);
+#else
+  dest->tv_sec_high = htonl(TV_NOHIGHSEC);
+#endif
+  dest->tv_sec_low = htonl(src->tv_sec);
+}
+
+/* ================================================== */
+
+#define FLOAT_EXP_BITS 7
+#define FLOAT_EXP_MIN (-(1 << (FLOAT_EXP_BITS - 1)))
+#define FLOAT_EXP_MAX (-FLOAT_EXP_MIN - 1)
+#define FLOAT_COEF_BITS ((int)sizeof (int32_t) * 8 - FLOAT_EXP_BITS)
+#define FLOAT_COEF_MIN (-(1 << (FLOAT_COEF_BITS - 1)))
+#define FLOAT_COEF_MAX (-FLOAT_COEF_MIN - 1)
+
+double
+UTI_FloatNetworkToHost(Float f)
+{
+  int32_t exp, coef;
+  uint32_t x;
+
+  x = ntohl(f.f);
+
+  exp = x >> FLOAT_COEF_BITS;
+  if (exp >= 1 << (FLOAT_EXP_BITS - 1))
+      exp -= 1 << FLOAT_EXP_BITS;
+  exp -= FLOAT_COEF_BITS;
+
+  coef = x % (1U << FLOAT_COEF_BITS);
+  if (coef >= 1 << (FLOAT_COEF_BITS - 1))
+      coef -= 1 << FLOAT_COEF_BITS;
+
+  return coef * pow(2.0, exp);
+}
+
+Float
+UTI_FloatHostToNetwork(double x)
+{
+  int32_t exp, coef, neg;
+  Float f;
+
+  if (x < 0.0) {
+    x = -x;
+    neg = 1;
+  } else if (x >= 0.0) {
+    neg = 0;
+  } else {
+    /* Save NaN as zero */
+    x = 0.0;
+    neg = 0;
+  }
+
+  if (x < 1.0e-100) {
+    exp = coef = 0;
+  } else if (x > 1.0e100) {
+    exp = FLOAT_EXP_MAX;
+    coef = FLOAT_COEF_MAX + neg;
+  } else {
+    exp = log(x) / log(2) + 1;
+    coef = x * pow(2.0, -exp + FLOAT_COEF_BITS) + 0.5;
+
+    assert(coef > 0);
+
+    /* we may need to shift up to two bits down */
+    while (coef > FLOAT_COEF_MAX + neg) {
+      coef >>= 1;
+      exp++;
+    }
+
+    if (exp > FLOAT_EXP_MAX) {
+      /* overflow */
+      exp = FLOAT_EXP_MAX;
+      coef = FLOAT_COEF_MAX + neg;
+    } else if (exp < FLOAT_EXP_MIN) {
+      /* underflow */
+      if (exp + FLOAT_COEF_BITS >= FLOAT_EXP_MIN) {
+        coef >>= FLOAT_EXP_MIN - exp;
+        exp = FLOAT_EXP_MIN;
+      } else {
+        exp = coef = 0;
+      }
+    }
+  }
+
+  /* negate back */
+  if (neg)
+    coef = (uint32_t)-coef << FLOAT_EXP_BITS >> FLOAT_EXP_BITS;
+
+  f.f = htonl((uint32_t)exp << FLOAT_COEF_BITS | coef);
+  return f;
+}
+
+/* ================================================== */
+
+int
+UTI_FdSetCloexec(int fd)
+{
+  int flags;
+
+  flags = fcntl(fd, F_GETFD);
+  if (flags != -1) {
+    flags |= FD_CLOEXEC;
+    return !fcntl(fd, F_SETFD, flags);
+  }
+
+  return 0;
+}
+
+/* ================================================== */
+
+int
+UTI_SetQuitSignalsHandler(void (*handler)(int))
+{
+  struct sigaction sa;
+
+  sa.sa_handler = handler;
+  sa.sa_flags = SA_RESTART;
+  if (sigemptyset(&sa.sa_mask) < 0)
+    return 0;
+
+#ifdef SIGINT
+  if (sigaction(SIGINT, &sa, NULL) < 0)
+    return 0;
+#endif
+#ifdef SIGTERM
+  if (sigaction(SIGTERM, &sa, NULL) < 0)
+    return 0;
+#endif
+#ifdef SIGQUIT
+  if (sigaction(SIGQUIT, &sa, NULL) < 0)
+    return 0;
+#endif
+#ifdef SIGHUP
+  if (sigaction(SIGHUP, &sa, NULL) < 0)
+    return 0;
+#endif
+
+  return 1;
+}
+
+/* ================================================== */
+
+char *
+UTI_PathToDir(const char *path)
+{
+  char *dir, *slash;
+
+  slash = strrchr(path, '/');
+
+  if (!slash)
+    return Strdup(".");
+
+  if (slash == path)
+    return Strdup("/");
+
+  dir = Malloc(slash - path + 1);
+  snprintf(dir, slash - path + 1, "%s", path);
+
+  return dir;
+}
+
+/* ================================================== */
+
+static int
+create_dir(char *p, mode_t mode, uid_t uid, gid_t gid)
+{
+  int status;
+  struct stat buf;
+
+  /* See if directory exists */
+  status = stat(p, &buf);
+
+  if (status < 0) {
+    if (errno != ENOENT) {
+      LOG(LOGS_ERR, "Could not access %s : %s", p, strerror(errno));
+      return 0;
+    }
+  } else {
+    if (S_ISDIR(buf.st_mode))
+      return 1;
+    LOG(LOGS_ERR, "%s is not directory", p);
+    return 0;
+  }
+
+  /* Create the directory */
+  if (mkdir(p, mode) < 0) {
+    LOG(LOGS_ERR, "Could not create directory %s : %s", p, strerror(errno));
+    return 0;
+  }
+
+  /* Set its owner */
+  if (chown(p, uid, gid) < 0) {
+    LOG(LOGS_ERR, "Could not change ownership of %s : %s", p, strerror(errno));
+    /* Don't leave it there with incorrect ownership */
+    rmdir(p);
+    return 0;
+  }
+
+  return 1;
+}
+
+/* ================================================== */
+/* Return 0 if the directory couldn't be created, 1 if it could (or
+   already existed) */
+int
+UTI_CreateDirAndParents(const char *path, mode_t mode, uid_t uid, gid_t gid)
+{
+  char *p;
+  int i, j, k, last;
+
+  /* Don't try to create current directory */
+  if (!strcmp(path, "."))
+    return 1;
+
+  p = (char *)Malloc(1 + strlen(path));
+
+  i = k = 0;
+  while (1) {
+    p[i++] = path[k++];
+
+    if (path[k] == '/' || !path[k]) {
+      /* Check whether its end of string, a trailing / or group of / */
+      last = 1;
+      j = k;
+      while (path[j]) {
+        if (path[j] != '/') {
+          /* Pick up a / into p[] thru the assignment at the top of the loop */
+          k = j - 1;
+          last = 0;
+          break;
+        }
+        j++;
+      }
+
+      p[i] = 0;
+
+      if (!create_dir(p, last ? mode : 0755, last ? uid : 0, last ? gid : 0)) {
+        Free(p);
+        return 0;
+      }
+
+      if (last)
+        break;
+    }
+
+    if (!path[k])
+      break;
+  }
+
+  Free(p);
+  return 1;
+}
+
+/* ================================================== */
+
+int
+UTI_CheckDirPermissions(const char *path, mode_t perm, uid_t uid, gid_t gid)
+{
+  struct stat buf;
+
+  if (stat(path, &buf)) {
+    LOG(LOGS_ERR, "Could not access %s : %s", path, strerror(errno));
+    return 0;
+  }
+
+  if (!S_ISDIR(buf.st_mode)) {
+    LOG(LOGS_ERR, "%s is not directory", path);
+    return 0;
+  }
+
+  if ((buf.st_mode & 0777) & ~perm) {
+    LOG(LOGS_ERR, "Wrong permissions on %s", path);
+    return 0;
+  }
+
+  if (buf.st_uid != uid) {
+    LOG(LOGS_ERR, "Wrong owner of %s (%s != %d)", path, "UID", uid);
+    return 0;
+  }
+
+  if (buf.st_gid != gid) {
+    LOG(LOGS_ERR, "Wrong owner of %s (%s != %d)", path, "GID", gid);
+    return 0;
+  }
+
+  return 1;
+}
+
+/* ================================================== */
+
+void
+UTI_DropRoot(uid_t uid, gid_t gid)
+{
+  /* Drop supplementary groups */
+  if (setgroups(0, NULL))
+    LOG_FATAL("setgroups() failed : %s", strerror(errno));
+
+  /* Set effective, saved and real group ID */
+  if (setgid(gid))
+    LOG_FATAL("setgid(%d) failed : %s", gid, strerror(errno));
+
+  /* Set effective, saved and real user ID */
+  if (setuid(uid))
+    LOG_FATAL("setuid(%d) failed : %s", uid, strerror(errno));
+
+  DEBUG_LOG("Dropped root privileges: UID %d GID %d", uid, gid);
+}
+
+/* ================================================== */
+
+#define DEV_URANDOM "/dev/urandom"
+
+void
+UTI_GetRandomBytesUrandom(void *buf, unsigned int len)
+{
+  static FILE *f = NULL;
+
+  if (!f)
+    f = fopen(DEV_URANDOM, "r");
+  if (!f)
+    LOG_FATAL("Can't open %s : %s", DEV_URANDOM, strerror(errno));
+  if (fread(buf, 1, len, f) != len)
+    LOG_FATAL("Can't read from %s", DEV_URANDOM);
+}
+
+/* ================================================== */
+
+#ifdef HAVE_GETRANDOM
+static void
+get_random_bytes_getrandom(char *buf, unsigned int len)
+{
+  static char rand_buf[256];
+  static unsigned int available = 0, disabled = 0;
+  unsigned int i;
+
+  for (i = 0; i < len; i++) {
+    if (!available) {
+      if (disabled)
+        break;
+
+      if (getrandom(rand_buf, sizeof (rand_buf), 0) != sizeof (rand_buf)) {
+        disabled = 1;
+        break;
+      }
+
+      available = sizeof (rand_buf);
+    }
+
+    buf[i] = rand_buf[--available];
+  }
+
+  if (i < len)
+    UTI_GetRandomBytesUrandom(buf, len);
+}
+#endif
+
+/* ================================================== */
+
+void
+UTI_GetRandomBytes(void *buf, unsigned int len)
+{
+#ifdef HAVE_ARC4RANDOM
+  arc4random_buf(buf, len);
+#elif defined(HAVE_GETRANDOM)
+  get_random_bytes_getrandom(buf, len);
+#else
+  UTI_GetRandomBytesUrandom(buf, len);
+#endif
+}
diff --git a/chrony_3_3/util.h b/chrony_3_3/util.h
new file mode 100644
index 0000000..40ff729
--- /dev/null
+++ b/chrony_3_3/util.h
@@ -0,0 +1,203 @@
+/*
+  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.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Various utility functions
+  */
+
+#ifndef GOT_UTIL_H
+#define GOT_UTIL_H
+
+#include "sysincl.h"
+
+#include "addressing.h"
+#include "ntp.h"
+#include "candm.h"
+#include "hash.h"
+
+/* Zero a timespec */
+extern void UTI_ZeroTimespec(struct timespec *ts);
+
+/* Check if a timespec is zero */
+extern int UTI_IsZeroTimespec(struct timespec *ts);
+
+/* Convert a timeval into a timespec */
+extern void UTI_TimevalToTimespec(struct timeval *tv, struct timespec *ts);
+
+/* Convert a timespec into a timeval */
+extern void UTI_TimespecToTimeval(struct timespec *ts, struct timeval *tv);
+
+/* Convert a timespec into a floating point number of seconds */
+extern double UTI_TimespecToDouble(struct timespec *ts);
+
+/* Convert a number of seconds expressed in floating point into a
+   timespec */
+extern void UTI_DoubleToTimespec(double d, struct timespec *ts);
+
+/* Normalise a timespec, by adding or subtracting seconds to bring
+   its nanosecond field into range */
+extern void UTI_NormaliseTimespec(struct timespec *ts);
+
+/* Convert a timeval into a floating point number of seconds */
+extern double UTI_TimevalToDouble(struct timeval *tv);
+
+/* Convert a number of seconds expressed in floating point into a
+   timeval */
+extern void UTI_DoubleToTimeval(double a, struct timeval *b);
+
+/* Normalise a struct timeval, by adding or subtracting seconds to bring
+   its microseconds field into range */
+extern void UTI_NormaliseTimeval(struct timeval *x);
+
+/* Returns -1 if a comes earlier than b, 0 if a is the same time as b,
+   and +1 if a comes after b */
+extern int UTI_CompareTimespecs(struct timespec *a, struct timespec *b);
+
+/* Calculate result = a - b */
+extern void UTI_DiffTimespecs(struct timespec *result, struct timespec *a, struct timespec *b);
+
+/* Calculate result = a - b and return as a double */
+extern double UTI_DiffTimespecsToDouble(struct timespec *a, struct timespec *b);
+
+/* Add a double increment to a timespec to get a new one. 'start' is
+   the starting time, 'end' is the result that we return.  This is
+   safe to use if start and end are the same */
+extern void UTI_AddDoubleToTimespec(struct timespec *start, double increment, struct timespec *end);
+
+/* Calculate the average and difference (as a double) of two timespecs */
+extern void UTI_AverageDiffTimespecs(struct timespec *earlier, struct timespec *later, struct timespec *average, double *diff);
+
+/* Calculate result = a - b + c */
+extern void UTI_AddDiffToTimespec(struct timespec *a, struct timespec *b, struct timespec *c, struct timespec *result);
+
+/* Convert a timespec into a temporary string, largely for diagnostic
+   display */
+extern char *UTI_TimespecToString(struct timespec *ts);
+
+/* Convert an NTP timestamp into a temporary string, largely for
+   diagnostic display */
+extern char *UTI_Ntp64ToString(NTP_int64 *ts);
+
+/* Convert ref_id into a temporary string, for diagnostics */
+extern char *UTI_RefidToString(uint32_t ref_id);
+
+/* Convert an IP address to string, for diagnostics */
+extern char *UTI_IPToString(IPAddr *ip);
+
+extern int UTI_StringToIP(const char *addr, IPAddr *ip);
+extern uint32_t UTI_IPToRefid(IPAddr *ip);
+extern uint32_t UTI_IPToHash(IPAddr *ip);
+extern void UTI_IPHostToNetwork(IPAddr *src, IPAddr *dest);
+extern void UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest);
+extern int UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask);
+
+extern void UTI_SockaddrToIPAndPort(struct sockaddr *sa, IPAddr *ip, unsigned short *port);
+extern int UTI_IPAndPortToSockaddr(IPAddr *ip, unsigned short port, struct sockaddr *sa);
+extern char *UTI_SockaddrToString(struct sockaddr *sa);
+extern const char *UTI_SockaddrFamilyToString(int family);
+
+extern char *UTI_TimeToLogForm(time_t t);
+
+/* Adjust time following a frequency/offset change */
+extern void UTI_AdjustTimespec(struct timespec *old_ts, struct timespec *when, struct timespec *new_ts, double *delta_time, double dfreq, double doffset);
+
+/* Get zero NTP timestamp with random bits below precision */
+extern void UTI_GetNtp64Fuzz(NTP_int64 *ts, int precision);
+
+extern double UTI_Ntp32ToDouble(NTP_int32 x);
+extern NTP_int32 UTI_DoubleToNtp32(double x);
+
+/* Zero an NTP timestamp */
+extern void UTI_ZeroNtp64(NTP_int64 *ts);
+
+/* Check if an NTP timestamp is zero */
+extern int UTI_IsZeroNtp64(NTP_int64 *ts);
+
+/* Compare two NTP timestamps.  Returns -1 if a is before b, 0 if a is equal to
+   b, and 1 if a is after b. */
+extern int UTI_CompareNtp64(NTP_int64 *a, NTP_int64 *b);
+
+/* Compare an NTP timestamp with up to three other timestamps.  Returns 0
+   if a is not equal to any of b1, b2, and b3, 1 otherwise. */
+extern int UTI_IsEqualAnyNtp64(NTP_int64 *a, NTP_int64 *b1, NTP_int64 *b2, NTP_int64 *b3);
+
+/* Convert a timespec into an NTP timestamp */
+extern void UTI_TimespecToNtp64(struct timespec *src, NTP_int64 *dest, NTP_int64 *fuzz);
+
+/* Convert an NTP timestamp into a timespec */
+extern void UTI_Ntp64ToTimespec(NTP_int64 *src, struct timespec *dest);
+
+/* Check if time + offset is sane */
+extern int UTI_IsTimeOffsetSane(struct timespec *ts, double offset);
+
+/* Get 2 raised to power of a signed integer */
+extern double UTI_Log2ToDouble(int l);
+
+extern void UTI_TimespecNetworkToHost(Timespec *src, struct timespec *dest);
+extern void UTI_TimespecHostToNetwork(struct timespec *src, Timespec *dest);
+
+extern double UTI_FloatNetworkToHost(Float x);
+extern Float UTI_FloatHostToNetwork(double x);
+
+/* Set FD_CLOEXEC on descriptor */
+extern int UTI_FdSetCloexec(int fd);
+
+extern int UTI_SetQuitSignalsHandler(void (*handler)(int));
+
+/* Get directory (as an allocated string) for a path */
+extern char *UTI_PathToDir(const char *path);
+
+/* Create a directory with a specified mode (umasked) and set its uid/gid.
+   Create also any parent directories that don't exist with mode 755 and
+   default uid/gid.  Returns 1 if created or already exists (even with
+   different mode/uid/gid), 0 otherwise. */
+extern int UTI_CreateDirAndParents(const char *path, mode_t mode, uid_t uid, gid_t gid);
+
+/* Check if a directory is secure.  It must not have other than the specified
+   permissions and its uid/gid must match the specified values. */
+extern int UTI_CheckDirPermissions(const char *path, mode_t perm, uid_t uid, gid_t gid);
+
+/* Set process user/group IDs and drop supplementary groups */
+extern void UTI_DropRoot(uid_t uid, gid_t gid);
+
+/* Fill buffer with random bytes from /dev/urandom */
+extern void UTI_GetRandomBytesUrandom(void *buf, unsigned int len);
+
+/* Fill buffer with random bytes from /dev/urandom or a faster source if it's
+   available (e.g. arc4random()), which may not necessarily be suitable for
+   generating long-term keys */
+extern void UTI_GetRandomBytes(void *buf, unsigned int len);
+
+/* Macros to get maximum and minimum of two values */
+#ifdef MAX
+#undef MAX
+#endif
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+/* Macro to clamp a value between two values */
+#define CLAMP(min, x, max) (MAX((min), MIN((x), (max))))
+
+#endif /* GOT_UTIL_H */
diff --git a/chrony_3_3/version.txt b/chrony_3_3/version.txt
new file mode 100644
index 0000000..eb39e53
--- /dev/null
+++ b/chrony_3_3/version.txt
@@ -0,0 +1 @@
+3.3