Compare commits

..

8 Commits

Author SHA1 Message Date
Miroslav Lichvar
aabb564320 doc: update NEWS 2016-01-19 08:15:15 +01:00
Miroslav Lichvar
df46e5ca5d ntp: restrict authentication of server/peer to specified key
When a server/peer was specified with a key number to enable
authentication with a symmetric key, packets received from the
server/peer were accepted if they were authenticated with any of
the keys contained in the key file and not just the specified key.

This allowed an attacker who knew one key of a client/peer to modify
packets from its servers/peers that were authenticated with other
keys in a man-in-the-middle (MITM) attack. For example, in a network
where each NTP association had a separate key and all hosts had only
keys they needed, a client of a server could not attack other clients
of the server, but it could attack the server and also attack its own
clients (i.e. modify packets from other servers).

To not allow the server/peer to be authenticated with other keys
extend the authentication test to check if the key ID in the received
packet is equal to the configured key number. As a consequence, it's
no longer possible to authenticate two peers to each other with two
different keys, both peers have to be configured to use the same key.

This issue was discovered by Matt Street of Cisco ASIG.
2016-01-19 08:15:12 +01:00
Miroslav Lichvar
370ba5e8fc doc: warn that unauthenticated peers are vulnerable to DoS attack 2016-01-19 08:14:46 +01:00
Miroslav Lichvar
463093803d doc: fix CVE-ID in NEWS
CVE-2015-1853 is for chrony, CVE-2015-1799 is for ntp.
2015-04-08 08:47:13 +02:00
Miroslav Lichvar
c4bedce1f4 doc: update NEWS 2015-04-07 16:35:16 +02:00
Miroslav Lichvar
79eacdb7e6 cmdmon: fix initialization of allocated reply slots
When allocating memory to save unacknowledged replies to authenticated
command requests, the last "next" pointer was not initialized to NULL.
When all allocated reply slots were used, the next reply could be
written to an invalid memory instead of allocating a new slot for it.

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

An attacker that has the command key and is allowed to access cmdmon
(only localhost is allowed by default) could exploit this to crash
chronyd or possibly execute arbitrary code with the privileges of the
chronyd process.
2015-04-07 16:35:16 +02:00
Miroslav Lichvar
d856bd34c4 ntp: protect authenticated symmetric associations against DoS attacks
An attacker knowing that NTP hosts A and B are peering with each other
(symmetric association) can send a packet with random timestamps to host
A with source address of B which will set the NTP state variables on A
to the values sent by the attacker. Host A will then send on its next
poll to B a packet with originate timestamp that doesn't match the
transmit timestamp of B and the packet will be dropped. If the attacker
does this periodically for both hosts, they won't be able to synchronize
to each other. It is a denial-of-service attack.

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

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

[1] https://www.eecis.udel.edu/~mills/onwire.html
2015-04-07 16:34:42 +02:00
317 changed files with 22842 additions and 54977 deletions

35
.gitignore vendored
View File

@@ -1,28 +1,21 @@
.deps
.vimrc
*.gcda
*.gcno
*.o
*.swp
*.dSYM
*.DS_Store
core.*
RELEASES
Makefile
chrony.conf.5
chrony.info
chrony.html
chrony.texi
chrony.txt
chronyc
chronyc.1
chronyd
chronyd.8
config.h
config.log
tags
/RELEASES
/Makefile
/chronyc
/chronyd
/config.h
/config.log
/doc/Makefile
/doc/*.html
/doc/*.man
/doc/*.man.in
/doc/*.txt
/getdate.c
/version.h
version.h
/test/simulation/clknetsim
/test/simulation/tmp
/test/unit/Makefile
/test/unit/*.test
/test/unit/*.o

View File

@@ -21,66 +21,71 @@
#
# Makefile template
SYSCONFDIR = @SYSCONFDIR@
BINDIR = @BINDIR@
SBINDIR = @SBINDIR@
LOCALSTATEDIR = @LOCALSTATEDIR@
CHRONYVARDIR = @CHRONYVARDIR@
DESTDIR =
SYSCONFDIR=@SYSCONFDIR@
BINDIR=@BINDIR@
SBINDIR=@SBINDIR@
MANDIR=@MANDIR@
INFODIR=@INFODIR@
DOCDIR=@DOCDIR@
LOCALSTATEDIR=@LOCALSTATEDIR@
CHRONYVARDIR=@CHRONYVARDIR@
CC = @CC@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
DESTDIR=
HASH_OBJ = @HASH_OBJ@
OBJS = util.o sched.o regress.o local.o \
sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \
sources.o sourcestats.o reference.o \
logging.o conf.o cmdmon.o keys.o \
nameserv.o nameserv_async.o manual.o addrfilt.o \
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
broadcast.o refclock.o refclock_phc.o refclock_pps.o \
refclock_shm.o refclock_sock.o tempcomp.o $(HASH_OBJ)
EXTRA_OBJS=@EXTRA_OBJECTS@
CLI_OBJS = client.o nameserv.o getdate.o cmdparse.o \
pktlength.o util.o $(HASH_OBJ)
ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS)
LDFLAGS = @LDFLAGS@
GETDATE_CFLAGS = @GETDATE_CFLAGS@
EXTRA_OBJS = @EXTRA_OBJS@
OBJS = addrfilt.o array.o clientlog.o cmdparse.o conf.o keys.o leapdb.o \
local.o logging.o main.o memory.o nameserv.o nameserv_async.o \
ntp_auth.o ntp_core.o ntp_ext.o ntp_io.o ntp_sources.o quantiles.o \
reference.o regress.o rtc.o samplefilt.o sched.o socket.o sources.o sourcestats.o \
stubs.o smooth.o sys.o sys_null.o tempcomp.o util.o $(EXTRA_OBJS)
EXTRA_CLI_OBJS = @EXTRA_CLI_OBJS@
CLI_OBJS = array.o client.o cmdparse.o getdate.o memory.o nameserv.o \
pktlength.o socket.o util.o $(EXTRA_CLI_OBJS)
ALL_OBJS = $(OBJS) $(CLI_OBJS)
LIBS = @LIBS@
EXTRA_LIBS = @EXTRA_LIBS@
EXTRA_CLI_LIBS = @EXTRA_CLI_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)
$(CC) $(CFLAGS) -o chronyd $(OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS)
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)
getdate.o: CFLAGS += $(GETDATE_CFLAGS)
client.o : client.c
$(CC) $(CFLAGS) $(CPPFLAGS) @READLINE_COMPILE@ -c $<
$(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
distclean : clean
$(MAKE) -C doc distclean
$(MAKE) -C test/unit distclean
-rm -f .DS_Store
-rm -f Makefile config.h config.log
-rm -f Makefile
-rm -f chrony.conf.5 chrony.texi chronyc.1 chronyd.8
clean :
$(MAKE) -C test/unit clean
-rm -f *.o *.s chronyc chronyd core.* *~
-rm -f *.gcda *.gcno
-rm -f *.o *.s chronyc chronyd core *~ chrony.info chrony.html chrony.txt
-rm -rf .deps
-rm -rf *.dSYM
getdate.c : getdate.y
getdate.c :
bison -o getdate.c getdate.y
# This can be used to force regeneration of getdate.c
@@ -90,10 +95,15 @@ getdate :
# For install, don't use the install command, because its switches
# seem to vary between systems.
install: chronyd chronyc
install: chronyd chronyc chrony.txt
[ -d $(DESTDIR)$(SYSCONFDIR) ] || mkdir -p $(DESTDIR)$(SYSCONFDIR)
[ -d $(DESTDIR)$(SBINDIR) ] || mkdir -p $(DESTDIR)$(SBINDIR)
[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
[ -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
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
[ -d $(DESTDIR)$(CHRONYVARDIR) ] || mkdir -p $(DESTDIR)$(CHRONYVARDIR)
if [ -f $(DESTDIR)$(SBINDIR)/chronyd ]; then rm -f $(DESTDIR)$(SBINDIR)/chronyd ; fi
if [ -f $(DESTDIR)$(BINDIR)/chronyc ]; then rm -f $(DESTDIR)$(BINDIR)/chronyc ; fi
@@ -101,13 +111,20 @@ install: chronyd chronyc
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
cp chrony.txt $(DESTDIR)$(DOCDIR)/chrony.txt
chmod 644 $(DESTDIR)$(DOCDIR)/chrony.txt
cp COPYING $(DESTDIR)$(DOCDIR)/COPYING
chmod 644 $(DESTDIR)$(DOCDIR)/COPYING
cp README $(DESTDIR)$(DOCDIR)/README
chmod 644 $(DESTDIR)$(DOCDIR)/README
cp chrony.1 $(DESTDIR)$(MANDIR)/man1
chmod 644 $(DESTDIR)$(MANDIR)/man1/chrony.1
cp chronyc.1 $(DESTDIR)$(MANDIR)/man1
chmod 644 $(DESTDIR)$(MANDIR)/man1/chronyc.1
cp chronyd.8 $(DESTDIR)$(MANDIR)/man8
chmod 644 $(DESTDIR)$(MANDIR)/man8/chronyd.8
cp chrony.conf.5 $(DESTDIR)$(MANDIR)/man5
chmod 644 $(DESTDIR)$(MANDIR)/man5/chrony.conf.5
%.o : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
@@ -115,24 +132,30 @@ install-docs :
%.s : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -S $<
quickcheck : chronyd chronyc
$(MAKE) -C test/unit check
cd test/simulation && ./run
cd test/system && ./run
check : chronyd chronyc
$(MAKE) -C test/unit check
cd test/simulation && ./run -i 20 -m 2
cd test/system && ./run
cd test/simulation && ./run
print-chronyd-objects :
@echo $(OBJS)
install-docs : docs
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
cp chrony.txt $(DESTDIR)$(DOCDIR)/chrony.txt
chmod 644 $(DESTDIR)$(DOCDIR)/chrony.txt
cp chrony.html $(DESTDIR)$(DOCDIR)/chrony.html
chmod 644 $(DESTDIR)$(DOCDIR)/chrony.html
[ -d $(DESTDIR)$(INFODIR) ] || mkdir -p $(DESTDIR)$(INFODIR)
cp chrony.info* $(DESTDIR)$(INFODIR)
chmod 644 $(DESTDIR)$(INFODIR)/chrony.info*
Makefile : Makefile.in configure
@echo
@echo Makefile needs to be regenerated, run ./configure
@echo
@exit 1
docs : chrony.txt chrony.html chrony.info
chrony.txt : chrony.texi
makeinfo --no-headers --number-sections -o chrony.txt chrony.texi
chrony.html : chrony.texi
command -v texi2html > /dev/null 2>&1 && texi2html chrony.texi || \
makeinfo --no-split --html --number-sections -o chrony.html chrony.texi
chrony.info : chrony.texi
makeinfo chrony.texi
.deps:
@mkdir .deps
@@ -140,6 +163,4 @@ Makefile : Makefile.in configure
.deps/%.d: %.c | .deps
@$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@
ifndef NODEPS
-include $(ALL_OBJS:%.o=.deps/%.d)
endif

561
NEWS
View File

@@ -1,567 +1,10 @@
New in version 4.8
==================
Enhancements
------------
* Add maxunreach option to limit selection of unreachable sources
* Add -u option to chronyc to drop root privileges (default chronyc
user is set by configure script)
Bug fixes
---------
* Hide chronyc socket to mitigate unsafe permissions change
* Fix refclock extpps option to work on Linux >= 6.15
* Validate refclock samples for reachability updates
New in version 4.7
==================
Enhancements
------------
* Add opencommands directive to select remote monitoring commands
* Add interval option to driftfile directive
* Add waitsynced and waitunsynced options to local directive
* Add sanity checks for integer values in configuration
* Add support for systemd Type=notify service
* Add RTC refclock driver
* Allow PHC refclock to be specified with network interface name
* Don't require multiple refclock samples per poll to simplify
filter configuration
* Keep refclock reachable when dropping samples with large delay
* Improve quantile-based filtering to adapt faster to larger delay
* Improve logging of selection failures
* Detect clock interference from other processes
* Try to reopen message log (-l option) on cyclelogs command
Bug fixes
---------
* Fix sourcedir reloading to not multiply sources
* Fix tracking offset after failed clock step
Removed features
----------------
* Drop support for NTS with Nettle < 3.6 and GnuTLS < 3.6.14
* Drop support for building without POSIX threads
New in version 4.6.1
====================
Enhancements
------------
* Add ntsaeads directive to enable only selected AEAD algorithms for NTS
Workarounds
-----------
* Negotiate use of compliant NTS keys with AES-128-GCM-SIV AEAD algorithm
(by default the keys are generated differently than in RFC 8915 for
compatibility with chrony server and client versions 4.4, 4.5, and 4.6)
* Switch to compliant NTS keys if first response from server is NTS NAK
New in version 4.6
==================
Enhancements
------------
* Add activate option to local directive to set activation threshold
* Add ipv4 and ipv6 options to server/pool/peer directive
* Add kod option to ratelimit directive for server KoD RATE support
* Add leapseclist directive to read NIST/IERS leap-seconds.list file
* Add ptpdomain directive to set PTP domain for NTP over PTP
* Allow disabling pidfile
* Improve copy server option to accept unsynchronised status instantly
* Log one selection failure on start
* Add offset command to modify source offset correction
* Add timestamp sources to ntpdata report
Bug fixes
---------
* Fix crash on sources reload during initstepslew or RTC initialisation
* Fix source refreshment to not repeat failed name resolving attempts
New in version 4.5
==================
Enhancements
------------
* Add support for AES-GCM-SIV in GnuTLS
* Add support for corrections from PTP transparent clocks
* Add support for systemd socket activation
Bug fixes
---------
* Fix presend in interleaved mode
* Fix reloading of modified sources from sourcedir
New in version 4.4
==================
Enhancements
------------
* Add support for AES-GCM-SIV with Nettle >= 3.9 to shorten NTS
cookies to avoid some length-specific blocking of NTP on Internet
* Add support for multiple refclocks using extpps option on one PHC
* Add maxpoll option to hwtimestamp directive to improve PHC tracking
with low packet rates
* Add hwtstimeout directive to configure timeout for late timestamps
* Handle late hardware transmit timestamps of NTP requests on all sockets
* Handle mismatched 32/64-bit time_t in SOCK refclock samples
* Improve source replacement
* Log important changes made by command requests (chronyc)
* Refresh address of NTP sources periodically
* Request nanosecond kernel RX timestamping on FreeBSD
* Set DSCP for IPv6 packets
* Shorten NTS-KE retry interval when network is down
* Update seccomp filter for musl
* Warn if loading keys from file with unexpected permissions
* Warn if source selection fails or falseticker is detected
* Add selectopts command to modify source-specific selection options
* Add timestamp sources to serverstats report and make its fields 64-bit
* Add -e option to chronyc to indicate end of response
New in version 4.3
==================
Enhancements
------------
* Add local option to refclock directive to stabilise system clock
with more stable free-running clock (e.g. TCXO, OCXO)
* Add maxdelayquant option to server/pool/peer directive to replace
maxdelaydevratio filter with long-term quantile-based filtering
* Add selection option to log directive
* Allow external PPS in PHC refclock without configurable pin
* Don't accept first interleaved response to minimise error in delay
* Don't use arc4random on Linux to avoid server performance loss
* Improve filter option to better handle missing NTP samples
* Improve stability with hardware timestamping and PHC refclock
* Update seccomp filter
Bug fixes
---------
* Fix waitsync command to reconnect when not getting response
New in version 4.2
==================
Enhancements
------------
* Add support for NTPv4 extension field improving synchronisation
stability and resolution of root delay and dispersion (experimental)
* Add support for NTP over PTP (experimental)
* Add support for AES-CMAC and hash functions in GnuTLS
* Improve server interleaved mode to be more reliable and support
multiple clients behind NAT
* Update seccomp filter
* Add statistics about interleaved mode to serverstats report
Bug fixes
---------
* Fix RTC support with 64-bit time_t on 32-bit Linux
* Fix seccomp filter to work correctly with bind*device directives
* Suppress kernel adjustments of system clock (dosynctodr) on illumos
Other changes
-------------
* Switch Solaris support to illumos
New in version 4.1
==================
Enhancements
------------
* Add support for NTS servers specified by IP address (matching
Subject Alternative Name in server certificate)
* Add source-specific configuration of trusted certificates
* Allow multiple files and directories with trusted certificates
* Allow multiple pairs of server keys and certificates
* Add copy option to server/pool directive
* Increase PPS lock limit to 40% of pulse interval
* Perform source selection immediately after loading dump files
* Reload dump files for addresses negotiated by NTS-KE server
* Update seccomp filter and add less restrictive level
* Restart ongoing name resolution on online command
Bug fixes
---------
* Fix responding to IPv4 command requests on FreeBSD
* Fix dump files to not include uncorrected offset
* Fix initstepslew to accept time from own NTP clients
* Reset NTP address and port when no longer negotiated by NTS-KE server
New in version 4.0
==================
Enhancements
------------
* Add support for Network Time Security (NTS) authentication
* Add support for AES-CMAC keys (AES128, AES256) with Nettle
* Add authselectmode directive to control selection of unauthenticated sources
* Add binddevice, bindacqdevice, bindcmddevice directives
* Add confdir directive to better support fragmented configuration
* Add sourcedir directive and "reload sources" command to support dynamic
NTP sources specified in files
* Add clockprecision directive
* Add dscp directive to set Differentiated Services Code Point (DSCP)
* Add -L option to limit log messages by severity
* Add -p option to print whole configuration with included files
* Add -U option to allow start under non-root user
* Allow maxsamples to be set to 1 for faster update with -q/-Q option
* Avoid replacing NTP sources with sources that have unreachable address
* Improve pools to repeat name resolution to get "maxsources" sources
* Improve source selection with trusted sources
* Improve NTP loop test to prevent synchronisation to itself
* Repeat iburst when NTP source is switched from offline state to online
* Update clock synchronisation status and leap status more frequently
* Update seccomp filter
* Add "add pool" command
* Add "reset sources" command to drop all measurements
* Add authdata command to print details about NTP authentication
* Add selectdata command to print details about source selection
* Add -N option and sourcename command to print original names of sources
* Add -a option to some commands to print also unresolved sources
* Add -k, -p, -r options to clients command to select, limit, reset data
Bug fixes
---------
* Don't set interface for NTP responses to allow asymmetric routing
* Handle RTCs that don't support interrupts
* Respond to command requests with correct address on multihomed hosts
Removed features
----------------
* Drop support for RIPEMD keys (RMD128, RMD160, RMD256, RMD320)
* Drop support for long (non-standard) MACs in NTPv4 packets (chrony 2.x
clients using non-MD5/SHA1 keys need to use option "version 3")
* Drop support for line editing with GNU Readline
New in version 3.5.1
====================
Security fixes
--------------
* Create new file when writing pidfile (CVE-2020-14367)
New in version 3.5
==================
Enhancements
------------
* Add support for more accurate reading of PHC on Linux 5.0
* Add support for hardware timestamping on interfaces with read-only
timestamping configuration
* Add support for memory locking and real-time priority on FreeBSD,
NetBSD, Solaris
* Update seccomp filter to work on more architectures
* Validate refclock driver options
Bug fixes
---------
* Fix bindaddress directive on FreeBSD
* Fix transposition of hardware RX timestamp on Linux 4.13 and later
* Fix building on non-glibc systems
New in version 3.4
==================
Enhancements
------------
* Add filter option to server/pool/peer directive
* Add minsamples and maxsamples options to hwtimestamp directive
* Add support for faster frequency adjustments in Linux 4.19
* Change default pidfile to /var/run/chrony/chronyd.pid to allow
chronyd without root privileges to remove it on exit
* Disable sub-second polling intervals for distant NTP sources
* Extend range of supported sub-second polling intervals
* Get/set IPv4 destination/source address of NTP packets on FreeBSD
* Make burst options and command useful with short polling intervals
* Modify auto_offline option to activate when sending request failed
* Respond from interface that received NTP request if possible
* Add onoffline command to switch between online and offline state
according to current system network configuration
* Improve example NetworkManager dispatcher script
Bug fixes
---------
* Avoid waiting in Linux getrandom system call
* Fix PPS support on FreeBSD and NetBSD
New in version 3.3
==================
Enhancements
------------
* Add burst option to server/pool directive
* Add stratum and tai options to refclock directive
* Add support for Nettle crypto library
* Add workaround for missing kernel receive timestamps on Linux
* Wait for late hardware transmit timestamps
* Improve source selection with unreachable sources
* Improve protection against replay attacks on symmetric mode
* Allow PHC refclock to use socket in /var/run/chrony
* Add shutdown command to stop chronyd
* Simplify format of response to manual list command
* Improve handling of unknown responses in chronyc
Bug fixes
---------
* Respond to NTPv1 client requests with zero mode
* Fix -x option to not require CAP_SYS_TIME under non-root user
* Fix acquisitionport directive to work with privilege separation
* Fix handling of socket errors on Linux to avoid high CPU usage
* Fix chronyc to not get stuck in infinite loop after clock step
New in version 3.2
==================
Enhancements
------------
* Improve stability with NTP sources and reference clocks
* Improve stability with hardware timestamping
* Improve support for NTP interleaved modes
* Control frequency of system clock on macOS 10.13 and later
* Set TAI-UTC offset of system clock with leapsectz directive
* Minimise data in client requests to improve privacy
* Allow transmit-only hardware timestamping
* Add support for new timestamping options introduced in Linux 4.13
* Add root delay, root dispersion and maximum error to tracking log
* Add mindelay and asymmetry options to server/peer/pool directive
* Add extpps option to PHC refclock to timestamp external PPS signal
* Add pps option to refclock directive to treat any refclock as PPS
* Add width option to refclock directive to filter wrong pulse edges
* Add rxfilter option to hwtimestamp directive
* Add -x option to disable control of system clock
* Add -l option to log to specified file instead of syslog
* Allow multiple command-line options to be specified together
* Allow starting without root privileges with -Q option
* Update seccomp filter for new glibc versions
* Dump history on exit by default with dumpdir directive
* Use hardening compiler options by default
Bug fixes
---------
* Don't drop PHC samples with low-resolution system clock
* Ignore outliers in PHC tracking, RTC tracking, manual input
* Increase polling interval when peer is not responding
* Exit with error message when include directive fails
* Don't allow slash after hostname in allow/deny directive/command
* Try to connect to all addresses in chronyc before giving up
New in version 3.1
==================
Enhancements
------------
* Add support for precise cross timestamping of PHC on Linux
* Add minpoll, precision, nocrossts options to hwtimestamp directive
* Add rawmeasurements option to log directive and modify measurements
option to log only valid measurements from synchronised sources
* Allow sub-second polling interval with NTP sources
Bug fixes
---------
* Fix time smoothing in interleaved mode
New in version 3.0
==================
Enhancements
------------
* Add support for software and hardware timestamping on Linux
* Add support for client/server and symmetric interleaved modes
* Add support for MS-SNTP authentication in Samba
* Add support for truncated MACs in NTPv4 packets
* Estimate and correct for asymmetric network jitter
* Increase default minsamples and polltarget to improve stability
with very low jitter
* Add maxjitter directive to limit source selection by jitter
* Add offset option to server/pool/peer directive
* Add maxlockage option to refclock directive
* Add -t option to chronyd to exit after specified time
* Add partial protection against replay attacks on symmetric mode
* Don't reset polling interval when switching sources to online state
* Allow rate limiting with very short intervals
* Improve maximum server throughput on Linux and NetBSD
* Remove dump files after start
* Add tab-completion to chronyc with libedit/readline
* Add ntpdata command to print details about NTP measurements
* Allow all source options to be set in add server/peer command
* Indicate truncated addresses/hostnames in chronyc output
* Print reference IDs as hexadecimal numbers to avoid confusion with
IPv4 addresses
Bug fixes
---------
* Fix crash with disabled asynchronous name resolving
New in version 2.4.1
====================
Bug fixes
---------
* Fix processing of kernel timestamps on non-Linux systems
* Fix crash with smoothtime directive
* Fix validation of refclock sample times
* Fix parsing of refclock directive
New in version 2.4
==================
Enhancements
------------
* Add orphan option to local directive for orphan mode compatible with ntpd
* Add distance option to local directive to set activation threshold
(1 second by default)
* Add maxdrift directive to set maximum allowed drift of system clock
* Try to replace NTP sources exceeding maximum distance
* Randomise source replacement to avoid getting stuck with bad sources
* Randomise selection of sources from pools on start
* Ignore reference timestamp as ntpd doesn't always set it correctly
* Modify tracking report to use same values as seen by NTP clients
* Add -c option to chronyc to write reports in CSV format
* Provide detailed manual pages
Bug fixes
---------
* Fix SOCK refclock to work correctly when not specified as last refclock
* Fix initstepslew and -q/-Q options to accept time from own NTP clients
* Fix authentication with keys using 512-bit hash functions
* Fix crash on exit when multiple signals are received
* Fix conversion of very small floating-point numbers in command packets
Removed features
----------------
* Drop documentation in Texinfo format
New in version 2.3
==================
Enhancements
------------
* Add support for NTP and command response rate limiting
* Add support for dropping root privileges on Mac OS X, FreeBSD, Solaris
* Add require and trust options for source selection
* Enable logchange by default (1 second threshold)
* Set RTC on Mac OS X with rtcsync directive
* Allow binding to NTP port after dropping root privileges on NetBSD
* Drop CAP_NET_BIND_SERVICE capability on Linux when NTP port is disabled
* Resolve names in separate process when seccomp filter is enabled
* Replace old records in client log when memory limit is reached
* Don't reveal local time and synchronisation state in client packets
* Don't keep client sockets open for longer than necessary
* Ignore poll in KoD RATE packets as ntpd doesn't always set it correctly
* Warn when using keys shorter than 80 bits
* Add keygen command to generate random keys easily
* Add serverstats command to report NTP and command packet statistics
Bug fixes
---------
* Fix clock correction after making step on Mac OS X
* Fix building on Solaris
New in version 2.2.1
====================
New in version 1.31.2
=====================
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
=====================

324
README
View File

@@ -3,148 +3,248 @@ 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.
Chrony is a pair of programs for maintaining the accuracy of computer
clocks.
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 continuously, or run on a virtual machine.
chronyd is a (background) daemon program that can be started at boot
time. This does most of the work.
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.
chronyc is a command-line interface program which can be used to
monitor chronyd's performance and to change various operating
parameters whilst it is running.
chronyd's main function is to obtain measurements of the true (UTC)
time from one of several sources, and correct the system clock
accordingly. It also works out the rate at which the system clock
gains or loses time and uses this information to keep it accurate
between measurements from the reference.
The reference time can be derived from Network Time Protocol (NTP)
servers, reference clocks, or wristwatch-and-keyboard (via chronyc).
The main source of information about the Network Time Protocol is
http://www.ntp.org.
It is designed so that it can work on computers which only have
intermittent access to reference sources, for example computers which
use a dial-up account to access the Internet or laptops. Of course, it
will work well on computers with permanent connections too.
In addition, on Linux it can monitor the system's real time clock
performance, so the system can maintain accurate time even across
reboots.
Typical accuracies available between 2 machines are
On an ethernet LAN : 100-200 microseconds, often much better
On a V32bis dial-up modem connection : 10's of milliseconds (from one
session to the next)
With a good reference clock the accuracy can reach one microsecond.
chronyd can also operate as an RFC1305-compatible NTP server and peer.
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
illumos. Closely related systems may work too. Any other system will
likely require a porting exercise.
Chrony can be successfully built and run on
1. Linux 2.2.x, 2.3.x, 2.4.x, 2.6.x, 3.x
2. Solaris 2.5/2.5.1/2.6/2.7/2.8 (various platforms)
3. SunOS 4.1.4 (Sparc 2 and Sparc 20)
4. BSD/386 v1.1 has been reported to work using the SunOS 4.1 driver.
5. NetBSD.
Any other system will require a porting exercise. You would need to
start from one of the existing system-specific drivers and look into
the quirks of certain system calls and the kernel on your target
system.
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.
compilation process should be automatic.
You will need an ANSI C compiler -- gcc is recommended.
The manual (in texinfo and text formats) describes how to set the
software up for the less straightforward cases.
What documentation is there?
============================
The distribution includes manual pages and a document containing
Frequently Asked Questions (FAQ).
A manual is supplied in Texinfo format (chrony.texi) and
ready-formatted plain text (chrony.txt) in the distribution.
The documentation is also available on the chrony web pages, accessible
There is also information available on the chrony web pages, accessible
through the URL
https://chrony-project.org/
http://chrony.tuxfamily.org/
License
=======
Where are new versions announced?
=================================
chrony is distributed under the GNU General Public License version 2.
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
Authors
=======
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.
Author
======
Richard P. Curnow <rc@rc0.org.uk>
Maintainers
===========
Miroslav Lichvar <mlichvar@redhat.com>
Acknowledgements
================
In writing the chronyd program, extensive use has been made of the NTPv3 (RFC
1305) and NTPv4 (RFC 5905) specification. The source code of the xntpd/ntpd
implementation written by Dennis Fergusson, Lars Mathiesen, David Mills, and
others has been used to check the details of the protocol.
The following people have provided patches and other major contributions
to chrony:
to the program :
Lonnie Abelbeck <lonnie@abelbeck.com>
Benny Lyne Amorsen <benny@amorsen.dk>
Andrew Bishop <amb@gedanken.demon.co.uk>
Vincent Blut <vincent.debian@free.fr>
Luca Boccassi <bluca@debian.org>
Stephan I. Boettcher <stephan@nevis1.columbia.edu>
David Bohman <debohman@gmail.com>
Anthony Brandon <anthony@amarulasolutions.com>
Goswin Brederlow <brederlo@informatik.uni-tuebingen.de>
Leigh Brown <leigh@solinno.co.uk>
Erik Bryer <ebryer@spots.ab.ca>
Jonathan Cameron <jic23@cam.ac.uk>
Bryan Christianson <bryan@whatroute.net>
Juliusz Chroboczek <jch@pps.jussieu.fr>
Paul Donald <newtwen+gitlab@gmail.com>
Dan Drown <dan-ntp@drown.org>
Kamil Dudka <kdudka@redhat.com>
Christian Ehrhardt <christian.ehrhardt@canonical.com>
Paul Elliott <pelliott@io.com>
Robert Fairley <rfairley@redhat.com>
Ahmad Fatoum <a.fatoum@pengutronix.de>
Andreas Fenkart <extern-afe@mission-embedded.com>
Stefan R. Filipek <srfilipek@gmail.com>
Andy Fiddaman <illumos@fiddaman.net>
Mike Fleetwood <mike@rockover.demon.co.uk>
Rob Gill <rrobgill@protonmail.com>
Alexander Gretencord <arutha@gmx.de>
Andrew Griffiths <agriffit@redhat.com>
Walter Haidinger <walter.haidinger@gmx.at>
Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
John Hasler <john@dhh.gt.org>
Tjalling Hattink <t.hattink@fugro.nl>
Liam Hatton <me@liamhatton.com>
Holger Hoffstätte <holger@applied-asynchrony.com>
Jachym Holecek <jakym@volny.cz>
Håkan Johansson <f96hajo@chalmers.se>
Jim Knoble <jmknoble@pobox.com>
Antti Jrvinen <costello@iki.fi>
Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Eric Lammerts <eric@lammerts.org>
Stefan Lucke <stefan@lucke.in-berlin.de>
Victor Lum <viclum@vanu.com>
Kevin Lyda <kevin@ie.suberic.net>
Paul Menzel <paulepanter@users.sourceforge.net>
Vladimir Michl <vladimir.michl@seznam.cz>
Victor Moroz <vim@prv.adlum.ru>
Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
Patrick Oppenlander <patrick.oppenlander@gmail.com>
Frank Otto <sandwichmacher@web.de>
Denny Page <dennypage@me.com>
Rupesh Patel <rupatel@redhat.com>
Chris Perl <cperl@janestreet.com>
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
Andreas Piesk <apiesk@virbus.de>
Shachar Raindel <shacharr@google.com>
Mike Ryan <msr@hsilop.net>
Baruch Siach <baruch@tkos.co.il>
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
Foster Snowhill <forst@forstwoof.ru>
Andreas Steinmetz <ast@domdv.de>
NAKAMURA Takumi <takumi@ps.sakura.ne.jp>
Timo Teras <timo.teras@iki.fi>
Bill Unruh <unruh@physics.ubc.ca>
Luke Valenta <lvalenta@cloudflare.com>
Stephen Wadeley <swadeley@redhat.com>
Bernhard Weiss <lisnablagh@web.de>
Wolfgang Weisselberg <weissel@netcologne.de>
Bernhard M. Wiedemann <bwiedemann@suse.de>
Joachim Wiedorn <ad_debian@joonet.de>
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de>
Michael Witten <mfwitten@gmail.com>
Doug Woodward <dougw@whistler.com>
Thomas Zajic <zlatko@zlatko.fdns.net>
Patch to add minstratum option
Many other people have contributed bug reports and suggestions. We are sorry
we cannot identify all of you individually.
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
Juliusz Chroboczek <jch@pps.jussieu.fr>
Fix install rule in Makefile if chronyd file is in use.
Paul Elliott <pelliott@io.com>
DNSchrony (in contrib directory), a tool for handling NTP servers
with variable IP addresses.
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.
Walter Haidinger <walter.haidinger@gmx.at>
Providing me with login access to a Linux installation where v1.12
wouldn't compile, so I could develop the fixes for v1.13. Also, for
providing the disc space so I can keep 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
Miroslav Lichvar <mlichvar@redhat.com>
Reference clock support
IPv6 support
Linux capabilities support
Leap second support
Improved source selection
Improved sample history trimming
Improved polling interval adjustment
Improved stability with temporary asymmetric delays
Temperature compensation
Many other bug fixes and improvements
Victor Moroz <vim@prv.adlum.ru>
Patch to support Linux with HZ!=100
Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
acquisitionport support
Frank Otto <sandwichmacher@web.de>
Handling arbitrary HZ values
Andreas Piesk <apiesk@virbus.de>
Patch to make chronyc use the readline library if available
Timo Teras <timo.teras@iki.fi>
Patch to reply correctly on multihomed hosts
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
Providing me with 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. I'm
sorry I can't identify all of you individually.

View File

@@ -30,36 +30,27 @@
#include "sysincl.h"
/* This type is used to represent an IPv4 address or IPv6 address.
Addresses which are not resolved yet can be represented with an ID.
All parts are in HOST order, NOT network order. */
#define IPADDR_UNSPEC 0
#define IPADDR_INET4 1
#define IPADDR_INET6 2
#define IPADDR_ID 3
typedef struct {
union {
uint32_t in4;
uint8_t in6[16];
uint32_t id;
} addr;
uint16_t family;
uint16_t _pad;
} IPAddr;
typedef struct {
IPAddr ip_addr;
uint16_t port;
} IPSockAddr;
typedef IPSockAddr NTP_Remote_Address;
#define INVALID_IF_INDEX -1
unsigned short port;
} NTP_Remote_Address;
typedef struct {
IPAddr ip_addr;
int if_index;
int sock_fd;
} NTP_Local_Address;

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997,1998,1999,2000,2001,2002,2005
* Copyright (C) Miroslav Lichvar 2009, 2015
* 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
@@ -62,7 +62,7 @@ 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 |
dst[i] = 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];
@@ -247,8 +247,6 @@ set_subnet_(ADF_AuthTable table,
set_subnet(&table->base6, ip6, 4, 0, new_state, delete_children) == ADF_SUCCESS)
return ADF_SUCCESS;
break;
default:
break;
}
return ADF_BADSUBNET;
@@ -361,29 +359,6 @@ ADF_IsAllowed(ADF_AuthTable table,
case IPADDR_INET6:
split_ip6(ip_addr, ip6);
return check_ip_in_node(&table->base6, ip6);
default:
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;
@@ -391,15 +366,114 @@ is_any_allowed(TableNode *node, State parent)
/* ================================================== */
int
ADF_IsAnyAllowed(ADF_AuthTable table, int family)
#if defined TEST
static void print_node(TableNode *node, uint32_t *addr, int ip_len, int shift, int subnet_bits)
{
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;
uint32_t new_addr[4];
int i;
TableNode *sub_node;
for (i=0; i<subnet_bits; i++) putchar(' ');
if (ip_len == 1)
printf("%d.%d.%d.%d",
((addr[0] >> 24) & 255),
((addr[0] >> 16) & 255),
((addr[0] >> 8) & 255),
((addr[0] ) & 255));
else {
for (i=0; i<4; i++) {
if (addr[i])
printf("%d.%d.%d.%d",
((addr[i] >> 24) & 255),
((addr[i] >> 16) & 255),
((addr[i] >> 8) & 255),
((addr[i] ) & 255));
putchar(i < 3 ? ':' : '\0');
}
}
printf("/%d : %s\n",
subnet_bits,
(node->state == ALLOW) ? "allow" :
(node->state == DENY) ? "deny" : "as parent");
if (node->extended) {
for (i=0; i<16; i++) {
sub_node = &(node->extended[i]);
new_addr[0] = addr[0];
new_addr[1] = addr[1];
new_addr[2] = addr[2];
new_addr[3] = addr[3];
new_addr[ip_len - 1 - shift / 32] |= ((uint32_t)i << (shift % 32));
print_node(sub_node, new_addr, ip_len, shift - 4, subnet_bits + 4);
}
}
}
static void print_table(ADF_AuthTable table)
{
uint32_t addr[4];
memset(addr, 0, sizeof (addr));
printf("IPv4 table:\n");
print_node(&table->base4, addr, 1, 28, 0);
memset(addr, 0, sizeof (addr));
printf("IPv6 table:\n");
print_node(&table->base6, addr, 4, 124, 0);
}
/* ================================================== */
int main (int argc, char **argv)
{
IPAddr ip;
ADF_AuthTable table;
table = ADF_CreateTable();
ip.family = IPADDR_INET4;
ip.addr.in4 = 0x7e800000;
ADF_Allow(table, &ip, 9);
ip.addr.in4 = 0x7ecc0000;
ADF_Deny(table, &ip, 14);
#if 0
ip.addr.in4 = 0x7f000001;
ADF_Deny(table, &ip, 32);
ip.addr.in4 = 0x7f000000;
ADF_Allow(table, &ip, 8);
#endif
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
ip.addr.in4 ^= 1;
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
ip.family = IPADDR_INET6;
memcpy(ip.addr.in6, "abcdefghijklmnop", 16);
ADF_Deny(table, &ip, 66);
ADF_Allow(table, &ip, 59);
memcpy(ip.addr.in6, "xbcdefghijklmnop", 16);
ADF_Deny(table, &ip, 128);
ip.addr.in6[15] ^= 3;
ADF_Allow(table, &ip, 127);
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
ip.addr.in4 ^= 1;
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
print_table(table);
ADF_DestroyTable(table);
return 0;
}
#endif /* defined TEST */

View File

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

145
array.c
View File

@@ -1,145 +0,0 @@
/*
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_RemoveElement(ARR_Instance array, unsigned int index)
{
void *e, *l;
e = ARR_GetElement(array, index);
l = ARR_GetElement(array, array->used - 1);
if (e < l)
memmove(e, (char *)e + array->elem_size, (char *)l - (char *)e);
array->used--;
realloc_array(array, array->used);
}
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;
}

59
array.h
View File

@@ -1,59 +0,0 @@
/*
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);
/* Remove element with given index */
extern void ARR_RemoveElement(ARR_Instance array, unsigned int index);
/* 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

159
broadcast.c Normal file
View File

@@ -0,0 +1,159 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Deal with broadcast server functions.
*/
#include "config.h"
#include "sysincl.h"
#include "memory.h"
#include "addressing.h"
#include "broadcast.h"
#include "sched.h"
#include "ntp.h"
#include "local.h"
#include "reference.h"
#include "util.h"
#include "ntp_io.h"
typedef struct {
NTP_Remote_Address addr;
NTP_Local_Address local_addr;
int interval;
} Destination;
static Destination *destinations = 0;
static int n_destinations = 0;
static int max_destinations = 0;
void
BRD_Initialise(void)
{
}
/* ================================================== */
void
BRD_Finalise(void)
{
}
/* ================================================== */
/* This is a cut-down version of what transmit_packet in ntp_core.c does */
static void
timeout_handler(void *arbitrary)
{
Destination *d = (Destination *) arbitrary;
NTP_Packet message;
/* Parameters read from reference module */
int version;
int leap;
int are_we_synchronised, our_stratum;
NTP_Leap leap_status;
uint32_t our_ref_id, ts_fuzz;
struct timeval our_ref_time;
double our_root_delay, our_root_dispersion;
struct timeval local_transmit;
version = 3;
LCL_ReadCookedTime(&local_transmit, NULL);
REF_GetReferenceParams(&local_transmit,
&are_we_synchronised, &leap_status,
&our_stratum,
&our_ref_id, &our_ref_time,
&our_root_delay, &our_root_dispersion);
if (are_we_synchronised) {
leap = (int) leap_status;
} else {
leap = LEAP_Unsynchronised;
}
message.lvm = ((leap << 6) &0xc0) | ((version << 3) & 0x38) | (MODE_BROADCAST & 0x07);
message.stratum = our_stratum;
message.poll = 6; /* FIXME: what should this be? */
message.precision = LCL_GetSysPrecisionAsLog();
/* If we're sending a client mode packet and we aren't synchronized yet,
we might have to set up artificial values for some of these parameters */
message.root_delay = UTI_DoubleToInt32(our_root_delay);
message.root_dispersion = UTI_DoubleToInt32(our_root_dispersion);
message.reference_id = htonl((NTP_int32) our_ref_id);
/* Now fill in timestamps */
UTI_TimevalToInt64(&our_ref_time, &message.reference_ts, 0);
message.originate_ts.hi = 0UL;
message.originate_ts.lo = 0UL;
message.receive_ts.hi = 0UL;
message.receive_ts.lo = 0UL;
ts_fuzz = UTI_GetNTPTsFuzz(message.precision);
LCL_ReadCookedTime(&local_transmit, NULL);
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts, ts_fuzz);
NIO_SendNormalPacket(&message, &d->addr, &d->local_addr);
/* Requeue timeout. Don't care if interval drifts gradually, so just do it
* at the end. */
SCH_AddTimeoutInClass((double) d->interval, 1.0, 0.02,
SCH_NtpBroadcastClass,
timeout_handler, (void *) d);
}
/* ================================================== */
void
BRD_AddDestination(IPAddr *addr, unsigned short port, int interval)
{
if (max_destinations == n_destinations) {
/* Expand array */
max_destinations += 8;
if (destinations) {
destinations = ReallocArray(Destination, max_destinations, destinations);
} else {
destinations = MallocArray(Destination, max_destinations);
}
}
destinations[n_destinations].addr.ip_addr = *addr;
destinations[n_destinations].addr.port = port;
destinations[n_destinations].local_addr.ip_addr.family = IPADDR_UNSPEC;
destinations[n_destinations].local_addr.sock_fd =
NIO_GetServerSocket(&destinations[n_destinations].addr);
destinations[n_destinations].interval = interval;
SCH_AddTimeoutInClass((double) interval, 1.0, 0.0,
SCH_NtpBroadcastClass,
timeout_handler, (void *)(destinations + n_destinations));
++n_destinations;
}

View File

@@ -2,36 +2,36 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Patrick Oppenlander 2024
*
* 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 leap second information.
Deal with broadcast server functions.
*/
#ifndef GOT_LEAPDB_H
#define GOT_LEAPDB_H
#ifndef GOT_BROADCAST_H
#define GOT_BROADCAST_H
#include "ntp.h"
#include "addressing.h"
extern void LDB_Initialise(void);
extern NTP_Leap LDB_GetLeap(time_t when, int *tai_offset);
extern void LDB_Finalise(void);
extern void BRD_Initialise(void);
extern void BRD_Finalise(void);
extern void BRD_AddDestination(IPAddr *addr, unsigned short port, int interval);
#endif /* GOT_BROADCAST_H */
#endif /* GOT_LEAPDB_H */

444
candm.h
View File

@@ -31,12 +31,14 @@
#include "sysincl.h"
#include "addressing.h"
#include "hash.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
@@ -86,49 +88,22 @@
#define REQ_MODIFY_MAXDELAYDEVRATIO 47
#define REQ_RESELECT 48
#define REQ_RESELECTDISTANCE 49
#define REQ_MODIFY_MAKESTEP 50
#define REQ_SMOOTHING 51
#define REQ_SMOOTHTIME 52
#define REQ_REFRESH 53
#define REQ_SERVER_STATS 54
#define REQ_CLIENT_ACCESSES_BY_INDEX2 55
#define REQ_LOCAL2 56
#define REQ_NTP_DATA 57
#define REQ_ADD_SERVER2 58
#define REQ_ADD_PEER2 59
#define REQ_ADD_SERVER3 60
#define REQ_ADD_PEER3 61
#define REQ_SHUTDOWN 62
#define REQ_ONOFFLINE 63
#define REQ_ADD_SOURCE 64
#define REQ_NTP_SOURCE_NAME 65
#define REQ_RESET_SOURCES 66
#define REQ_AUTH_DATA 67
#define REQ_CLIENT_ACCESSES_BY_INDEX3 68
#define REQ_SELECT_DATA 69
#define REQ_RELOAD_SOURCES 70
#define REQ_DOFFSET2 71
#define REQ_MODIFY_SELECTOPTS 72
#define REQ_MODIFY_OFFSET 73
#define REQ_LOCAL3 74
#define N_REQUEST_TYPES 75
#define N_REQUEST_TYPES 50
/* Structure used to exchange timespecs independent of time_t size */
/* Special utoken value used to log on with first exchange being the
password. (This time value has long since gone by) */
#define SPECIAL_UTOKEN 0x10101010
/* Structure used to exchange timevals independent on size of time_t */
typedef struct {
uint32_t tv_sec_high;
uint32_t tv_sec_low;
uint32_t tv_nsec;
} Timespec;
} Timeval;
/* This is used in tv_sec_high for 32-bit timestamps */
#define TV_NOHIGHSEC 0x7fffffff
/* Structure for 64-bit integers (not requiring 64-bit alignment) */
typedef struct {
uint32_t high;
uint32_t low;
} Integer64;
/* 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 */
@@ -140,10 +115,6 @@ typedef struct {
pktlength.c, to get the number of bytes that ought to be
transmitted for each packet type. */
typedef struct {
int32_t EOR;
} REQ_Null;
typedef struct {
IPAddr mask;
IPAddr address;
@@ -217,24 +188,18 @@ typedef struct {
} REQ_Modify_Maxupdateskew;
typedef struct {
int32_t limit;
Float threshold;
Timeval ts;
int32_t EOR;
} REQ_Modify_Makestep;
} REQ_Logon;
typedef struct {
Timespec ts;
Timeval ts;
int32_t EOR;
} REQ_Settime;
typedef struct {
int32_t on_off;
int32_t stratum;
Float distance;
int32_t orphan;
Float activate;
Float wait_synced;
Float wait_unsynced;
int32_t EOR;
} REQ_Local;
@@ -243,11 +208,19 @@ typedef struct {
int32_t EOR;
} REQ_Manual;
typedef struct {
int32_t EOR;
} REQ_N_Sources;
typedef struct {
int32_t index;
int32_t EOR;
} REQ_Source_Data;
typedef struct {
int32_t EOR;
} REQ_Rekey;
typedef struct {
IPAddr ip;
int32_t subnet_bits;
@@ -259,54 +232,23 @@ typedef struct {
int32_t EOR;
} REQ_Ac_Check;
/* Source types in NTP source requests */
#define REQ_ADDSRC_SERVER 1
#define REQ_ADDSRC_PEER 2
#define REQ_ADDSRC_POOL 3
/* 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
#define REQ_ADDSRC_NTS 0x200
#define REQ_ADDSRC_COPY 0x400
#define REQ_ADDSRC_EF_EXP_MONO_ROOT 0x800
#define REQ_ADDSRC_EF_EXP_NET_CORRECTION 0x1000
#define REQ_ADDSRC_IPV4 0x2000
#define REQ_ADDSRC_IPV6 0x4000
typedef struct {
uint32_t type;
uint8_t name[256];
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;
uint32_t nts_port;
Float max_delay;
Float max_delay_ratio;
Float max_delay_dev_ratio;
Float min_delay;
Float asymmetry;
Float offset;
uint32_t flags;
int32_t filter_length;
uint32_t cert_set;
Float max_delay_quant;
int32_t max_unreach;
int32_t EOR;
} REQ_NTP_Source;
@@ -315,87 +257,83 @@ typedef struct {
int32_t EOR;
} REQ_Del_Source;
typedef struct {
int32_t EOR;
} REQ_WriteRtc;
typedef struct {
Float dfreq;
int32_t EOR;
} REQ_Dfreq;
typedef struct {
Float doffset;
int32_t sec;
int32_t usec;
int32_t EOR;
} REQ_Doffset;
typedef struct {
int32_t EOR;
} REQ_Tracking;
typedef struct {
uint32_t index;
int32_t EOR;
} REQ_Sourcestats;
typedef struct {
int32_t EOR;
} REQ_RTCReport;
typedef struct {
int32_t EOR;
} REQ_TrimRTC;
typedef struct {
int32_t EOR;
} REQ_CycleLogs;
typedef struct {
IPAddr ip;
uint32_t bits_specd;
} REQ_SubnetsAccessed_Subnet;
/* This is based on the response size rather than the
request size */
#define MAX_CLIENT_ACCESSES 8
typedef struct {
uint32_t first_index;
uint32_t n_clients;
uint32_t min_hits;
uint32_t reset;
uint32_t n_indices;
int32_t EOR;
} REQ_ClientAccessesByIndex;
typedef struct {
int32_t EOR;
} REQ_ManualList;
typedef struct {
int32_t index;
int32_t EOR;
} REQ_ManualDelete;
typedef struct {
int32_t EOR;
} REQ_MakeStep;
typedef struct {
int32_t EOR;
} REQ_Activity;
typedef struct {
int32_t EOR;
} REQ_Reselect;
typedef struct {
Float distance;
int32_t EOR;
} REQ_ReselectDistance;
#define REQ_SMOOTHTIME_RESET 0
#define REQ_SMOOTHTIME_ACTIVATE 1
typedef struct {
int32_t option;
int32_t EOR;
} REQ_SmoothTime;
typedef struct {
IPAddr ip_addr;
int32_t EOR;
} REQ_NTPData;
typedef struct {
IPAddr ip_addr;
int32_t EOR;
} REQ_NTPSourceName;
typedef struct {
IPAddr ip_addr;
int32_t EOR;
} REQ_AuthData;
typedef struct {
uint32_t index;
int32_t EOR;
} REQ_SelectData;
/* Mask and options reuse the REQ_ADDSRC flags */
typedef struct {
IPAddr address;
uint32_t ref_id;
uint32_t mask;
uint32_t options;
int32_t EOR;
} REQ_Modify_SelectOpts;
typedef struct {
IPAddr address;
uint32_t ref_id;
Float new_offset;
int32_t EOR;
} REQ_Modify_Offset;
/* ================================================== */
#define PKT_TYPE_CMD_REQUEST 1
@@ -424,18 +362,7 @@ typedef struct {
subnets accessed and client accesses
Version 6 : added padding to requests to prevent amplification attack,
changed maximum number of samples in manual list to 16, 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
(two times), delta offset, and manual timestamp, added new fields and
flags to NTP source request and report, made length of manual list constant,
added new commands: authdata, ntpdata, onoffline, refresh, reset,
selectdata, serverstats, shutdown, sourcename
changed maximum number of samples in manual list to 16
*/
#define PROTO_VERSION_NUMBER 6
@@ -449,8 +376,8 @@ typedef struct {
#define PROTO_VERSION_PADDING 6
/* The maximum length of padding in request packet, currently
defined by CLIENT_ACCESSES_BY_INDEX3 */
#define MAX_PADDING_LENGTH 484
defined by CLIENT_ACCESSES_BY_INDEX and MANUAL_LIST */
#define MAX_PADDING_LENGTH 396
/* ================================================== */
@@ -464,11 +391,10 @@ typedef struct {
(count up from zero for same sequence
number) */
uint32_t sequence; /* Client's sequence number */
uint32_t pad1;
uint32_t pad2;
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* Command token (to prevent replay attack) */
union {
REQ_Null null;
REQ_Online online;
REQ_Offline offline;
REQ_Burst burst;
@@ -481,36 +407,52 @@ typedef struct {
REQ_Modify_Minstratum modify_minstratum;
REQ_Modify_Polltarget modify_polltarget;
REQ_Modify_Maxupdateskew modify_maxupdateskew;
REQ_Modify_Makestep modify_makestep;
REQ_Logon logon;
REQ_Settime settime;
REQ_Local local;
REQ_Manual manual;
REQ_N_Sources n_sources;
REQ_Source_Data source_data;
REQ_Rekey rekey;
REQ_Allow_Deny allow_deny;
REQ_Ac_Check ac_check;
REQ_NTP_Source ntp_source;
REQ_Del_Source del_source;
REQ_WriteRtc writertc;
REQ_Dfreq dfreq;
REQ_Doffset doffset;
REQ_Tracking tracking;
REQ_Sourcestats sourcestats;
REQ_RTCReport rtcreport;
REQ_TrimRTC trimrtc;
REQ_CycleLogs cyclelogs;
REQ_ClientAccessesByIndex client_accesses_by_index;
REQ_ManualList manual_list;
REQ_ManualDelete manual_delete;
REQ_MakeStep make_step;
REQ_Activity activity;
REQ_Reselect reselect;
REQ_ReselectDistance reselect_distance;
REQ_SmoothTime smoothtime;
REQ_NTPData ntp_data;
REQ_NTPSourceName ntp_source_name;
REQ_AuthData auth_data;
REQ_SelectData select_data;
REQ_Modify_SelectOpts modify_select_opts;
REQ_Modify_Offset modify_offset;
} 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. */
/* The following fields only set the maximum size of the packet.
There are no holes between them and the actual data. */
/* Padding used to prevent traffic amplification */
uint8_t padding[MAX_PADDING_LENGTH];
/* Authentication data */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Request;
/* ================================================== */
/* Authority codes for command types */
#define PERMIT_OPEN 0
#define PERMIT_LOCAL 1
#define PERMIT_AUTH 2
/* ================================================== */
/* Reply codes */
@@ -526,21 +468,7 @@ typedef struct {
#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 RPY_NTP_SOURCE_NAME 19
#define RPY_AUTH_DATA 20
#define RPY_CLIENT_ACCESSES_BY_INDEX3 21
#define RPY_SERVER_STATS2 22
#define RPY_SELECT_DATA 23
#define RPY_SERVER_STATS3 24
#define RPY_SERVER_STATS4 25
#define RPY_NTP_DATA2 26
#define N_REPLY_TYPES 27
#define N_REPLY_TYPES 13
/* Status codes */
#define STT_SUCCESS 0
@@ -553,7 +481,8 @@ typedef struct {
#define STT_BADSUBNET 7
#define STT_ACCESSALLOWED 8
#define STT_ACCESSDENIED 9
#define STT_NOHOSTACCESS 10 /* Deprecated */
/* Deprecated */
#define STT_NOHOSTACCESS 10
#define STT_SOURCEALREADYKNOWN 11
#define STT_TOOMANYSOURCES 12
#define STT_NORTC 13
@@ -563,7 +492,6 @@ typedef struct {
#define STT_INVALIDAF 17
#define STT_BADPKTVERSION 18
#define STT_BADPKTLENGTH 19
#define STT_INVALIDNAME 21
typedef struct {
int32_t EOR;
@@ -578,12 +506,15 @@ typedef struct {
#define RPY_SD_MD_PEER 1
#define RPY_SD_MD_REF 2
#define RPY_SD_ST_SELECTED 0
#define RPY_SD_ST_NONSELECTABLE 1
#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_UNSELECTED 4
#define RPY_SD_ST_SELECTABLE 5
#define RPY_SD_ST_CANDIDATE 4
#define RPY_SD_ST_OUTLIER 5
#define RPY_SD_FLAG_NOSELECT 0x1
#define RPY_SD_FLAG_PREFER 0x2
typedef struct {
IPAddr ip_addr;
@@ -605,7 +536,7 @@ typedef struct {
IPAddr ip_addr;
uint16_t stratum;
uint16_t leap_status;
Timespec ref_time;
Timeval ref_time;
Float current_correction;
Float last_offset;
Float rms_offset;
@@ -633,7 +564,7 @@ typedef struct {
} RPY_Sourcestats;
typedef struct {
Timespec ref_time;
Timeval ref_time;
uint16_t n_samples;
uint16_t n_runs;
uint32_t span_seconds;
@@ -643,7 +574,7 @@ typedef struct {
} RPY_Rtc;
typedef struct {
Float offset;
uint32_t centiseconds;
Float dfreq_ppm;
Float new_afreq_ppm;
int32_t EOR;
@@ -651,18 +582,18 @@ typedef struct {
typedef struct {
IPAddr ip;
uint32_t ntp_hits;
uint32_t nke_hits;
uint32_t cmd_hits;
uint32_t ntp_drops;
uint32_t nke_drops;
uint32_t cmd_drops;
int8_t ntp_interval;
int8_t nke_interval;
int8_t cmd_interval;
int8_t ntp_timeout_interval;
uint32_t bits_specd;
uint32_t bitmap[8];
} RPY_SubnetsAccessed_Subnet;
typedef struct {
IPAddr ip;
uint32_t client_hits;
uint32_t peer_hits;
uint32_t cmd_hits_auth;
uint32_t cmd_hits_normal;
uint32_t cmd_hits_bad;
uint32_t last_ntp_hit_ago;
uint32_t last_nke_hit_ago;
uint32_t last_cmd_hit_ago;
} RPY_ClientAccesses_Client;
@@ -674,32 +605,10 @@ typedef struct {
int32_t EOR;
} RPY_ClientAccessesByIndex;
typedef struct {
Integer64 ntp_hits;
Integer64 nke_hits;
Integer64 cmd_hits;
Integer64 ntp_drops;
Integer64 nke_drops;
Integer64 cmd_drops;
Integer64 log_drops;
Integer64 ntp_auth_hits;
Integer64 ntp_interleaved_hits;
Integer64 ntp_timestamps;
Integer64 ntp_span_seconds;
Integer64 ntp_daemon_rx_timestamps;
Integer64 ntp_daemon_tx_timestamps;
Integer64 ntp_kernel_rx_timestamps;
Integer64 ntp_kernel_tx_timestamps;
Integer64 ntp_hw_rx_timestamps;
Integer64 ntp_hw_tx_timestamps;
Integer64 reserved[4];
int32_t EOR;
} RPY_ServerStats;
#define MAX_MANUAL_LIST_SAMPLES 16
typedef struct {
Timespec when;
Timeval when;
Float slewed_offset;
Float orig_offset;
Float residual;
@@ -720,101 +629,6 @@ typedef struct {
int32_t EOR;
} RPY_Activity;
#define RPY_SMT_FLAG_ACTIVE 0x1
#define RPY_SMT_FLAG_LEAPONLY 0x2
typedef struct {
uint32_t flags;
Float offset;
Float freq_ppm;
Float wander_ppm;
Float last_update_ago;
Float remaining_time;
int32_t EOR;
} RPY_Smoothing;
#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 total_good_count;
uint32_t total_kernel_tx_ts;
uint32_t total_kernel_rx_ts;
uint32_t total_hw_tx_ts;
uint32_t total_hw_rx_ts;
uint32_t reserved[4];
int32_t EOR;
} RPY_NTPData;
typedef struct {
uint8_t name[256];
int32_t EOR;
} RPY_NTPSourceName;
#define RPY_AD_MD_NONE 0
#define RPY_AD_MD_SYMMETRIC 1
#define RPY_AD_MD_NTS 2
typedef struct {
uint16_t mode;
uint16_t key_type;
uint32_t key_id;
uint16_t key_length;
uint16_t ke_attempts;
uint32_t last_ke_ago;
uint16_t cookies;
uint16_t cookie_length;
uint16_t nak;
uint16_t pad;
int32_t EOR;
} RPY_AuthData;
#define RPY_SD_OPTION_NOSELECT 0x1
#define RPY_SD_OPTION_PREFER 0x2
#define RPY_SD_OPTION_TRUST 0x4
#define RPY_SD_OPTION_REQUIRE 0x8
typedef struct {
uint32_t ref_id;
IPAddr ip_addr;
uint8_t state_char;
uint8_t authentication;
uint8_t leap;
uint8_t pad;
uint16_t conf_options;
uint16_t eff_options;
uint32_t last_sample_ago;
Float score;
Float lo_limit;
Float hi_limit;
int32_t EOR;
} RPY_SelectData;
typedef struct {
uint8_t version;
uint8_t pkt_type;
@@ -827,9 +641,9 @@ typedef struct {
uint16_t pad2;
uint16_t pad3;
uint32_t sequence; /* Echo of client's sequence number */
uint32_t pad4;
uint32_t pad5;
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* New command token (only if command was successfully
authenticated) */
union {
RPY_Null null;
RPY_N_Sources n_sources;
@@ -839,16 +653,14 @@ typedef struct {
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;
RPY_NTPSourceName ntp_source_name;
RPY_AuthData auth_data;
RPY_SelectData select_data;
} data; /* Reply specific parameters */
/* authentication of the packet, there is no hole after the actual data
from the data union, this field only sets the maximum auth size */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Reply;
/* ================================================== */

71
chrony.1 Normal file
View File

@@ -0,0 +1,71 @@
.TH CHRONY 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
.SH NAME
chrony \- programs for keeping computer clocks accurate
.SH SYNOPSIS
\fBchronyc\fR [\fIOPTIONS\fR]
\fBchronyd\fR [\fIOPTIONS\fR]
.SH DESCRIPTION
\fBchrony\fR is a pair of programs for keeping computer clocks accurate.
\fIchronyd\fR is a background (daemon) program and \fIchronyc\fR is a
command-line interface to it. Time reference sources for chronyd can be
RFC1305 NTP servers, human (via keyboard and \fIchronyc\fR), or the computer's
real-time clock at boot time (Linux only). chronyd can determine the rate at
which the computer gains or loses time and compensate for it while no external
reference is present. Its use of NTP servers can be switched on and off
(through \fIchronyc\fR) to support computers with dial-up/intermittent access
to the Internet, and it can also act as an RFC1305-compatible NTP server.
.SH USAGE
\fIchronyc\fR is a command-line interface program which can be used to
monitor \fIchronyd\fR's performance and to change various operating
parameters whilst it is running.
\fIchronyd\fR's main function is to obtain measurements of the true (UTC)
time from one of several sources, and correct the system clock
accordingly. It also works out the rate at which the system clock
gains or loses time and uses this information to keep it accurate
between measurements from the reference.
The reference time can be derived from either Network Time Protocol
(NTP) servers, reference clocks, or wristwatch-and-keyboard (via \fIchronyc\fR).
The main source of information about the Network Time Protocol is
\fIhttp://www.ntp.org\fR.
It is designed so that it can work on computers which only have
intermittent access to reference sources, for example computers which
use a dial-up account to access the Internet or laptops. Of course, it
will work well on computers with permanent connections too.
In addition, on Linux it can monitor the system's real time clock
performance, so the system can maintain accurate time even across
reboots.
Typical accuracies available between 2 machines are
On an ethernet LAN : 100-200 microseconds, often much better
On a V32bis dial-up modem connection : 10's of milliseconds (from one
session to the next)
With a good reference clock the accuracy can reach one microsecond.
\fIchronyd\fR can also operate as an RFC1305-compatible NTP server and peer.
.SH "SEE ALSO"
.BR chronyc(1),
.BR chrony.conf(5),
.BR chronyd(8)
.I http://chrony.tuxfamily.org/
.SH AUTHOR
Richard Curnow <rc@rc0.org.uk>
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part
of "The Missing Man Pages Project". Please see
\fIhttp://www.netmeister.org/misc/m2p2/index.html\fR for details.
The complete chrony documentation is supplied in texinfo format.

55
chrony.conf.5.in Normal file
View File

@@ -0,0 +1,55 @@
.TH chrony.conf 5 "@MAN_DATE@" "chrony @VERSION@" "Configuration Files"
.SH NAME
chrony.conf \- chronyd configuration file
.SH SYNOPSIS
.B @SYSCONFDIR@/chrony.conf
.SH DESCRIPTION
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
clocks. \fIchronyd\fR is a background daemon program that can be started at
boot time.
Assuming that you have found some servers, you need to set up a
configuration file to run \fIchrony\fR. The (compiled-in) default location
for this file is \fB@SYSCONFDIR@/chrony.conf\fR. Assuming that your ntp servers
are called `a.b.c' and `d.e.f', your \fBchrony.conf\fR file could contain
as a minimum
server a.b.c
server d.e.f
server g.h.i
However, you will probably want to include some of the other directives
described in detail in the documentation supplied with the distribution
(\fIchrony.txt\fR and \fIchrony.texi\fR). The following directives may be
particularly useful : `driftfile', `generatecommandkey', `keyfile', `makestep'.
Also, the `iburst' server option is useful to speed up the initial
synchronization. The smallest useful configuration file would look something
like
server a.b.c iburst
server d.e.f iburst
server g.h.i iburst
keyfile @SYSCONFDIR@/chrony.keys
generatecommandkey
driftfile @CHRONYVARDIR@/drift
makestep 10 3
.SH "SEE ALSO"
.BR chrony(1),
.BR chronyc(1),
.BR chronyd(8)
.I http://chrony.tuxfamily.org/
.SH AUTHOR
Richard Curnow <rc@rc0.org.uk>
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part of "The Missing
Man Pages Project". Please see \fIhttp://www.netmeister.org/misc/m2p2/index.html\fR
for details.
The complete chrony documentation is supplied in texinfo format.

5172
chrony.texi.in Normal file

File diff suppressed because it is too large Load Diff

73
chrony_timex.h Normal file
View File

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

75
chronyc.1.in Normal file
View File

@@ -0,0 +1,75 @@
.TH CHRONYC 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
.SH NAME
chronyc \- command-line interface for chronyd
.SH SYNOPSIS
.B chronyc
[\fIOPTIONS\fR]
.SH DESCRIPTION
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
clocks.
\fBchronyc\fR is a command-line interface program which can be used to
monitor \fIchronyd\fR's performance and to change various operating
parameters whilst it is running.
.SH USAGE
A detailed description of all commands supported by \fBchronyc\fR is available
via the documentation supplied with the distribution (\fIchrony.txt\fR and
\fIchrony.texi\fR).
.SH OPTIONS
A summary of the options supported by \fBchronyc\fR is included below.
.TP
\fB\-h\fR \fIhostname\fR
specify hostname (default 127.0.0.1)
.TP
\fB\-p\fR \fIport-number\fR
specify port-number
.TP
\fB\-n\fR
display raw IP addresses (don't attempt to look up hostnames)
.TP
\fB\-4\fR
resolve hostnames only to IPv4 addresses
.TP
\fB\-6\fR
resolve hostnames only to IPv6 addresses
.TP
\fB\-m\fR
allow multiple commands to be specified on the command line. Each argument
will be interpreted as a whole command.
.TP
\fB\-f\fR \fIconf-file\fR
This option can be used to specify an alternate location for the
configuration file (default \fI@SYSCONFDIR@/chrony.conf\fR). The configuration file is
needed for the \fB-a\fR option.
.TP
\fB\-a\fR
With this option chronyc will try to authenticate automatically on
start. It will read the configuration file, read the command key from the
keyfile and run the authhash and password commands.
.TP
\fIcommand\fR
specify command. If no command is given, chronyc will read commands
interactively.
.SH BUGS
To report bugs, please visit \fIhttp://chrony.tuxfamily.org\fR
.SH "SEE ALSO"
.BR chronyd(8),
.BR chrony(1)
.I http://chrony.tuxfamily.org/
.SH AUTHOR
Richard Curnow <rc@rc0.org.uk>
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part of "The Missing
Man Pages Project". Please see \fIhttp://www.netmeister.org/misc/m2p2/index.html\fR
for details.
The complete chrony documentation is supplied in texinfo format.

154
chronyd.8.in Normal file
View File

@@ -0,0 +1,154 @@
.TH CHRONYD 8 "@MAN_DATE@" "chrony @VERSION@" "System Administration"
.SH NAME
chronyd \- chrony background daemon
.SH SYNOPSIS
.B chronyd
[\fIOPTIONS\fR] [\fIconfiguration commands\fR]
.SH DESCRIPTION
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
clocks. \fBchronyd\fR is a background daemon program that can be started at boot
time.
\fBchronyd\fR is a daemon which runs in background on the
system. It obtains measurements (e.g. via the network) of the
system's offset relative to other systems, and adjusts the system
time accordingly. For isolated systems, the user can periodically
enter the correct time by hand (using \fIchronyc\fR). In either case,
\fBchronyd\fR determines the rate at which the computer
gains or loses time, and compensates for this.
.SH USAGE
\fBchronyd\fR is usually started at boot-time and requires superuser
privileges.
If \fBchronyd\fR has been installed to its default location
\fI@SBINDIR@/chronyd\fR, starting it is simply a matter of entering the
command:
\fI@SBINDIR@/chronyd\fR
Information messages and warnings will be logged to syslog.
If no configuration commands are specified on the command line,
\fBchronyd\fR will read the commands from the configuration file
(default \fI@SYSCONFDIR@/chrony.conf\fR).
.SH OPTIONS
A summary of the options supported by \fBchronyd\fR is included below.
.TP
\fB\-P\fR \fIpriority\fR
This option will select the SCHED_FIFO real-time scheduler at the specified
priority (which must be between 0 and 100). This mode is supported only on
Linux.
.TP
.B \-m
This option will lock chronyd into RAM so that it will never be paged out.
This mode is only supported on Linux.
.TP
.B \-n
When run in this mode, the program will not detach itself from the
terminal.
.TP
.B \-d
When run in this mode, the program will not detach itself from the
terminal, and all messages will be sent to the terminal instead of
to syslog. When \fBchronyd\fR was compiled with debugging support,
this option can be used twice to print also debugging messages.
.TP
\fB\-f\fR \fIconf-file\fR
This option can be used to specify an alternate location for the
configuration file (default \fI@SYSCONFDIR@/chrony.conf\fR).
.TP
.B \-r
This option will reload sample histories for each of the servers being used.
These histories are created by using the \fIdump\fR command in \fIchronyc\fR,
or by setting the \fIdumponexit\fR directive in the configuration file. This
option is useful if you want to stop and restart \fBchronyd\fR briefly for any
reason, e.g. to install a new version. However, it only makes sense on
systems where the kernel can maintain clock compensation whilst not under
\fBchronyd\fR's control. The only version where this happens so far is Linux.
On systems where this is not the case, e.g. Solaris and SunOS the option
should not be used.
.TP
.B \-R
When this option is used, the \fIinitstepslew\fR directive and the
\fImakestep\fR directive used with a positive limit will be ignored. This
option is useful when restarting \fBchronyd\fR and can be used in conjunction
with the \fB-r\fR option.
.TP
.B \-s
This option will set the system clock from the computer's real-time
clock. This is analogous to supplying the \fI-s\fR flag to the
\fI/sbin/hwclock\fR program during the Linux boot sequence.
Support for real-time clocks is limited at present - the criteria
are described in the section on the \fIrtcfile\fR directive in the
documentation supplied with the distribution.
If used in conjunction with the \fB-r\fR flag, \fBchronyd\fR will attempt
to preserve the old samples after setting the system clock from
the real time clock (RTC). This can be used to allow \fBchronyd\fR to
perform long term averaging of the gain or loss rate across system
reboots, and is useful for dial-up systems that are shut down when
not in use. For this to work well, it relies on \fBchronyd\fR having
been able to determine accurate statistics for the difference
between the RTC and system clock last time the computer was on.
If \fBchronyd\fR doesn't support the RTC on your computer or there is no RTC
installed, the system clock will be set with this option forward to the time of
the last modification of the drift file (specified by the \fIdriftfile\fR
directive) to restore the system time at which \fBchronyd\fR was previously
stopped.
.TP
\fB\-u\fR \fIuser\fR
This option sets the name of the user to which will \fBchronyd\fR switch to
drop root privileges if compiled with Linux capabilities support (default
\fB@DEFAULT_USER@\fR).
.TP
.B \-q
When run in this mode, chronyd will set the system clock once
and exit. It will not detach from the terminal.
.TP
.B \-Q
This option is similar to \fB\-q\fR, but it will only print the offset and
not correct the clock.
.TP
.B \-v
This option displays \fBchronyd\fR's version number to the terminal and exits
.TP
.B \-4
Resolve hostnames only to IPv4 addresses and create only IPv4 sockets.
.TP
.B \-6
Resolve hostnames only to IPv6 addresses and create only IPv6 sockets.
.SH FILES
\fI@SYSCONFDIR@/chrony.conf\fR
.SH BUGS
To report bugs, please visit \fIhttp://chrony.tuxfamily.org/\fR
.SH "SEE ALSO"
\fBchronyd\fR is documented in detail in the documentation supplied with the
distribution (\fIchrony.txt\fR and \fIchrony.texi\fR).
.BR chrony(1),
.BR chronyc(1),
.BR chrony.conf(5),
.BR hwclock(8),
.BR ntpd(8)
.I http://chrony.tuxfamily.org/
.SH AUTHOR
Richard Curnow <rc@rc0.org.uk>
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part
of "The Missing Man Pages Project". Please see
\fIhttp://www.netmeister.org/misc/m2p2/index.html\fR for details.
The complete chrony documentation is supplied in texinfo format.

3698
client.c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -31,43 +31,55 @@
#include "sysincl.h"
#include "reports.h"
typedef enum {
CLG_NTP = 0,
CLG_NTSKE,
CLG_CMDMON,
} CLG_Service;
typedef enum {
CLG_PASS = 0,
CLG_DROP,
CLG_KOD,
} CLG_Limit;
/* Enough to hold flags for 256 hosts in a class C */
typedef uint32_t CLG_Bitmap[8];
extern void CLG_Initialise(void);
extern void CLG_Finalise(void);
extern int CLG_GetClientIndex(IPAddr *client);
extern int CLG_LogServiceAccess(CLG_Service service, IPAddr *client, struct timespec *now);
extern CLG_Limit CLG_LimitServiceRate(CLG_Service service, int index);
extern void CLG_UpdateNtpStats(int auth, NTP_Timestamp_Source rx_ts_src,
NTP_Timestamp_Source tx_ts_src);
extern int CLG_GetNtpMinPoll(void);
extern void CLG_LogNTPClientAccess(IPAddr *client, time_t now);
extern void CLG_LogNTPPeerAccess(IPAddr *client, time_t now);
/* Functions to save and retrieve timestamps for server interleaved mode */
extern void CLG_SaveNtpTimestamps(NTP_int64 *rx_ts, struct timespec *tx_ts,
NTP_Timestamp_Source tx_src);
extern void CLG_UndoNtpTxTimestampSlew(NTP_int64 *rx_ts, struct timespec *tx_ts);
extern void CLG_UpdateNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts,
NTP_Timestamp_Source tx_src);
extern int CLG_GetNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts,
NTP_Timestamp_Source *tx_src);
extern void CLG_DisableNtpTimestamps(NTP_int64 *rx_ts);
/* When logging command packets, there are several subtypes */
typedef enum {
CLG_CMD_AUTH, /* authenticated */
CLG_CMD_NORMAL, /* normal */
CLG_CMD_BAD_PKT /* bad version or packet length */
} CLG_Command_Type;
extern void CLG_LogCommandAccess(IPAddr *client, CLG_Command_Type type, time_t now);
/* And some reporting functions, for use by chronyc. */
/* TBD */
typedef enum {
CLG_SUCCESS, /* All is well */
CLG_EMPTYSUBNET, /* No hosts logged in requested subnet */
CLG_BADSUBNET, /* Subnet requested is not 0, 8, 16 or 24 bits */
CLG_INACTIVE, /* Facility not active */
CLG_INDEXTOOLARGE /* Node index is higher than number of nodes present */
} CLG_Status;
/* For bits=0, 8, 16, flag which immediate subnets of that subnet are
known. For bits=24, flag which hosts in that subnet are known.
Other values, return 0 (failed) */
extern CLG_Status CLG_GetSubnetBitmap(IPAddr *subnet, int bits, CLG_Bitmap result);
extern CLG_Status
CLG_GetClientAccessReportByIP(IPAddr *ip, RPT_ClientAccess_Report *report, time_t now);
CLG_Status
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report,
time_t now, unsigned long *n_indices);
/* And an iterating function, to call 'fn' for each client or peer
that has accessed us since 'since'. */
extern void CLG_IterateNTPClients
(void (*fn)(IPAddr *client, void *arb),
void *arb,
time_t since);
extern int CLG_GetNumberOfIndices(void);
extern int CLG_GetClientAccessReportByIndex(int index, int reset, uint32_t min_hits,
RPT_ClientAccessByIndex_Report *report,
struct timespec *now);
extern void CLG_GetServerStatsReport(RPT_ServerStatsReport *report);
#endif /* GOT_CLIENTLOG_H */

48
cmac.h
View File

@@ -1,48 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019
*
* 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 CMAC.
*/
#ifndef GOT_CMAC_H
#define GOT_CMAC_H
/* Avoid overlapping with the hash enumeration */
typedef enum {
CMC_INVALID = 0,
CMC_AES128 = 13,
CMC_AES256 = 14,
} CMC_Algorithm;
typedef struct CMC_Instance_Record *CMC_Instance;
extern int CMC_GetKeyLength(CMC_Algorithm algorithm);
extern CMC_Instance CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key,
int length);
extern int CMC_Hash(CMC_Instance inst, const void *in, int in_len,
unsigned char *out, int out_len);
extern void CMC_DestroyInstance(CMC_Instance inst);
#endif

View File

@@ -1,189 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2021
*
* 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.
*
**********************************************************************
=======================================================================
CMAC using the GnuTLS library
*/
#include "config.h"
#include "sysincl.h"
#include <gnutls/crypto.h>
#include "cmac.h"
#include "hash.h"
#include "logging.h"
#include "memory.h"
struct CMC_Instance_Record {
gnutls_mac_algorithm_t algorithm;
gnutls_hmac_hd_t mac;
};
/* ================================================== */
static int instance_counter = 0;
static int gnutls_initialised = 0;
/* ================================================== */
static void
init_gnutls(void)
{
int r;
if (gnutls_initialised)
return;
r = gnutls_global_init();
if (r < 0)
LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
DEBUG_LOG("Initialised");
gnutls_initialised = 1;
}
/* ================================================== */
static void
deinit_gnutls(void)
{
assert(gnutls_initialised);
gnutls_global_deinit();
gnutls_initialised = 0;
DEBUG_LOG("Deinitialised");
}
/* ================================================== */
static gnutls_mac_algorithm_t
get_mac_algorithm(CMC_Algorithm algorithm)
{
switch (algorithm) {
case CMC_AES128:
return GNUTLS_MAC_AES_CMAC_128;
case CMC_AES256:
return GNUTLS_MAC_AES_CMAC_256;
default:
return GNUTLS_MAC_UNKNOWN;
}
}
/* ================================================== */
int
CMC_GetKeyLength(CMC_Algorithm algorithm)
{
gnutls_mac_algorithm_t malgo = get_mac_algorithm(algorithm);
int len;
if (malgo == GNUTLS_MAC_UNKNOWN)
return 0;
len = gnutls_hmac_get_key_size(malgo);
if (len < 0)
return 0;
return len;
}
/* ================================================== */
CMC_Instance
CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key, int length)
{
gnutls_hmac_hd_t handle;
CMC_Instance inst;
int r;
if (instance_counter == 0)
init_gnutls();
if (length <= 0 || length != CMC_GetKeyLength(algorithm))
goto error;
r = gnutls_hmac_init(&handle, get_mac_algorithm(algorithm), key, length);
if (r < 0) {
DEBUG_LOG("Could not initialise %s : %s", "mac", gnutls_strerror(r));
goto error;
}
inst = MallocNew(struct CMC_Instance_Record);
inst->algorithm = get_mac_algorithm(algorithm);
inst->mac = handle;
instance_counter++;
return inst;
error:
if (instance_counter == 0)
deinit_gnutls();
return NULL;
}
/* ================================================== */
int
CMC_Hash(CMC_Instance inst, const void *in, int in_len, unsigned char *out, int out_len)
{
unsigned char buf[MAX_HASH_LENGTH];
int hash_len;
if (in_len < 0 || out_len < 0)
return 0;
hash_len = gnutls_hmac_get_len(inst->algorithm);
if (out_len > hash_len)
out_len = hash_len;
if (hash_len > sizeof (buf))
return 0;
if (gnutls_hmac(inst->mac, in, in_len) < 0) {
/* Reset the state */
gnutls_hmac_output(inst->mac, buf);
return 0;
}
gnutls_hmac_output(inst->mac, buf);
memcpy(out, buf, out_len);
return out_len;
}
/* ================================================== */
void
CMC_DestroyInstance(CMC_Instance inst)
{
gnutls_hmac_deinit(inst->mac, NULL);
Free(inst);
instance_counter--;
if (instance_counter == 0)
deinit_gnutls();
}

View File

@@ -1,117 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019
*
* 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 AES128 and AES256 CMAC in Nettle.
*/
#include "config.h"
#include "sysincl.h"
#include <nettle/cmac.h>
#include "cmac.h"
#include "memory.h"
struct CMC_Instance_Record {
int key_length;
union {
struct cmac_aes128_ctx aes128;
struct cmac_aes256_ctx aes256;
} context;
};
/* ================================================== */
int
CMC_GetKeyLength(CMC_Algorithm algorithm)
{
if (algorithm == CMC_AES128)
return AES128_KEY_SIZE;
else if (algorithm == CMC_AES256)
return AES256_KEY_SIZE;
return 0;
}
/* ================================================== */
CMC_Instance
CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key, int length)
{
CMC_Instance inst;
if (length <= 0 || length != CMC_GetKeyLength(algorithm))
return NULL;
inst = MallocNew(struct CMC_Instance_Record);
inst->key_length = length;
switch (length) {
case AES128_KEY_SIZE:
cmac_aes128_set_key(&inst->context.aes128, key);
break;
case AES256_KEY_SIZE:
cmac_aes256_set_key(&inst->context.aes256, key);
break;
default:
assert(0);
}
return inst;
}
/* ================================================== */
int
CMC_Hash(CMC_Instance inst, const void *in, int in_len, unsigned char *out, int out_len)
{
if (in_len < 0 || out_len < 0)
return 0;
if (out_len > CMAC128_DIGEST_SIZE)
out_len = CMAC128_DIGEST_SIZE;
switch (inst->key_length) {
case AES128_KEY_SIZE:
cmac_aes128_update(&inst->context.aes128, in_len, in);
cmac_aes128_digest(&inst->context.aes128, out_len, out);
break;
case AES256_KEY_SIZE:
cmac_aes256_update(&inst->context.aes256, in_len, in);
cmac_aes256_digest(&inst->context.aes256, out_len, out);
break;
default:
assert(0);
}
return out_len;
}
/* ================================================== */
void
CMC_DestroyInstance(CMC_Instance inst)
{
Free(inst);
}

2417
cmdmon.c

File diff suppressed because it is too large Load Diff

View File

@@ -29,11 +29,10 @@
#include "addressing.h"
extern void CAM_Initialise(void);
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);

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2013-2014, 2016, 2021, 2025
* Copyright (C) Miroslav Lichvar 2013
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -34,323 +34,164 @@
#include "cmdparse.h"
#include "memory.h"
#include "nameserv.h"
#include "ntp.h"
#include "util.h"
/* ================================================== */
#define SSCANF_IN_RANGE(s, f, x, n, min, max) \
(sscanf((s), (f), (x), (n)) == 1 && *(x) >= (min) && *(x) <= (max))
/* ================================================== */
CPS_Status
CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
{
char *hostname, *cmd;
uint32_t ef_type;
int n, sel_option;
int ok, n, done;
CPS_Status result;
src->family = IPADDR_UNSPEC;
src->port = SRC_DEFAULT_PORT;
src->params.minpoll = SRC_DEFAULT_MINPOLL;
src->params.maxpoll = SRC_DEFAULT_MAXPOLL;
src->params.connectivity = SRC_ONLINE;
src->params.auto_offline = 0;
src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
src->params.burst = 0;
src->params.iburst = 0;
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
src->params.version = 0;
src->params.max_sources = SRC_DEFAULT_MAXSOURCES;
src->params.min_samples = SRC_DEFAULT_MINSAMPLES;
src->params.max_samples = SRC_DEFAULT_MAXSAMPLES;
src->params.max_unreach = SRC_DEFAULT_MAXUNREACH;
src->params.filter_length = 0;
src->params.interleaved = 0;
src->params.sel_options = 0;
src->params.nts = 0;
src->params.nts_port = SRC_DEFAULT_NTSPORT;
src->params.copy = 0;
src->params.ext_fields = 0;
src->params.authkey = INACTIVE_AUTHKEY;
src->params.cert_set = SRC_DEFAULT_CERTSET;
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.max_delay_quant = 0.0;
src->params.min_delay = 0.0;
src->params.asymmetry = SRC_DEFAULT_ASYMMETRY;
src->params.offset = 0.0;
src->params.online = 1;
src->params.auto_offline = 0;
src->params.iburst = 0;
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
src->params.sel_option = SRC_SelectNormal;
result = CPS_Success;
hostname = line;
line = CPS_SplitWord(line);
if (!*hostname)
return CPS_MissingArgument;
if (!*hostname) {
result = CPS_BadHost;
ok = 0;
} else {
/* Parse subfields */
ok = 1;
done = 0;
do {
cmd = line;
line = CPS_SplitWord(line);
src->name = hostname;
if (*cmd) {
if (!strcasecmp(cmd, "port")) {
if (sscanf(line, "%hu%n", &src->port, &n) != 1) {
result = CPS_BadPort;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "minpoll")) {
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1) {
result = CPS_BadMinpoll;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "maxpoll")) {
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1) {
result = CPS_BadMaxpoll;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "presend")) {
if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1) {
result = CPS_BadPresend;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1) {
result = CPS_BadMaxdelaydevratio;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "maxdelayratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) {
result = CPS_BadMaxdelayratio;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "maxdelay")) {
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1) {
result = CPS_BadMaxdelay;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "key")) {
if (sscanf(line, "%lu%n", &src->params.authkey, &n) != 1 ||
src->params.authkey == INACTIVE_AUTHKEY) {
result = CPS_BadKey;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "offline")) {
src->params.online = 0;
/* Parse options */
for (; *line; line += n) {
cmd = line;
line = CPS_SplitWord(line);
n = 0;
} else if (!strcasecmp(cmd, "auto_offline")) {
src->params.auto_offline = 1;
} else if (!strcasecmp(cmd, "iburst")) {
src->params.iburst = 1;
if (!strcasecmp(cmd, "auto_offline")) {
src->params.auto_offline = 1;
} else if (!strcasecmp(cmd, "burst")) {
src->params.burst = 1;
} else if (!strcasecmp(cmd, "copy")) {
src->params.copy = 1;
} else if (!strcasecmp(cmd, "iburst")) {
src->params.iburst = 1;
} else if (!strcasecmp(cmd, "offline")) {
src->params.connectivity = SRC_OFFLINE;
} else if (!strcasecmp(cmd, "certset")) {
if (sscanf(line, "%"SCNu32"%n", &src->params.cert_set, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "key")) {
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
src->params.authkey == INACTIVE_AUTHKEY)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "asymmetry")) {
if (sscanf(line, "%lf%n", &src->params.asymmetry, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "extfield")) {
if (sscanf(line, "%"SCNx32"%n", &ef_type, &n) != 1)
return CPS_InvalidValue;
switch (ef_type) {
case NTP_EF_EXP_MONO_ROOT:
src->params.ext_fields |= NTP_EF_FLAG_EXP_MONO_ROOT;
break;
case NTP_EF_EXP_NET_CORRECTION:
src->params.ext_fields |= NTP_EF_FLAG_EXP_NET_CORRECTION;
break;
default:
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "minstratum")) {
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1) {
result = CPS_BadMinstratum;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "polltarget")) {
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1) {
result = CPS_BadPolltarget;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "noselect")) {
src->params.sel_option = SRC_SelectNoselect;
} else if (!strcasecmp(cmd, "prefer")) {
src->params.sel_option = SRC_SelectPrefer;
} else {
result = CPS_BadOption;
ok = 0;
done = 1;
}
} else {
done = 1;
}
} else if (!strcasecmp(cmd, "filter")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.filter_length, &n, 0, INT_MAX))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "ipv4")) {
src->family = IPADDR_INET4;
} else if (!strcasecmp(cmd, "ipv6")) {
src->family = IPADDR_INET6;
} else if (!strcasecmp(cmd, "maxdelay")) {
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "maxdelayratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "maxdelayquant")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_quant, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "maxpoll")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.maxpoll, &n, -32, 32))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "maxsamples")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.max_samples, &n, 0, INT_MAX))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "maxsources")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.max_sources, &n, 1, INT_MAX))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "maxunreach")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.max_unreach, &n, 0, INT_MAX))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "mindelay")) {
if (sscanf(line, "%lf%n", &src->params.min_delay, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "minpoll")) {
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "minsamples")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.min_samples, &n, 0, INT_MAX))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "minstratum")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.min_stratum, &n, 0, NTP_MAX_STRATUM))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "nts")) {
src->params.nts = 1;
} else if (!strcasecmp(cmd, "ntsport")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.nts_port, &n, 0, 65535))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "offset")) {
if (sscanf(line, "%lf%n", &src->params.offset, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "port")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->port, &n, 0, 65535))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "polltarget")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.poll_target, &n, 1, INT_MAX))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "presend")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.presend_minpoll, &n, -32, 32))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "version")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.version, &n, 1, NTP_VERSION))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "xleave")) {
src->params.interleaved = 1;
} else if ((sel_option = CPS_GetSelectOption(cmd)) != 0) {
src->params.sel_options |= sel_option;
} else {
return CPS_InvalidOption;
}
} while (!done);
}
return CPS_Success;
}
/* ================================================== */
int
CPS_GetSelectOption(char *option)
{
if (!strcasecmp(option, "noselect")) {
return SRC_SELECT_NOSELECT;
} else if (!strcasecmp(option, "prefer")) {
return SRC_SELECT_PREFER;
} else if (!strcasecmp(option, "require")) {
return SRC_SELECT_REQUIRE;
} else if (!strcasecmp(option, "trust")) {
return SRC_SELECT_TRUST;
}
return 0;
}
/* ================================================== */
int
CPS_ParseAllowDeny(char *line, int *all, IPAddr *ip, int *subnet_bits)
{
char *p, *net, *slash;
uint32_t a, b, c;
int bits, len, n;
p = CPS_SplitWord(line);
if (strcmp(line, "all") == 0) {
*all = 1;
net = p;
p = CPS_SplitWord(p);
} else {
*all = 0;
net = line;
if (ok) {
src->name = strdup(hostname);
}
/* Make sure there are no other arguments */
if (*p)
return 0;
/* No specified address or network means all IPv4 and IPv6 addresses */
if (!*net) {
ip->family = IPADDR_UNSPEC;
*subnet_bits = 0;
return 1;
}
slash = strchr(net, '/');
if (slash) {
if (sscanf(slash + 1, "%d%n", &bits, &len) != 1 || slash[len + 1] || bits < 0)
return 0;
*slash = '\0';
} else {
bits = -1;
}
if (UTI_StringToIP(net, ip)) {
if (bits >= 0)
*subnet_bits = bits;
else
*subnet_bits = ip->family == IPADDR_INET6 ? 128 : 32;
return 1;
}
/* Check for a shortened IPv4 network notation using only 1, 2, or 3 decimal
numbers. This is different than the numbers-and-dots notation accepted
by inet_aton()! */
a = b = c = 0;
n = sscanf(net, "%"PRIu32"%n.%"PRIu32"%n.%"PRIu32"%n", &a, &len, &b, &len, &c, &len);
if (n > 0 && !net[len]) {
if (a > 255 || b > 255 || c > 255)
return 0;
ip->family = IPADDR_INET4;
ip->addr.in4 = (a << 24) | (b << 16) | (c << 8);
if (bits >= 0)
*subnet_bits = bits;
else
*subnet_bits = n * 8;
return 1;
}
/* The last possibility is a hostname */
if (bits < 0 && DNS_Name2IPAddress(net, ip, 1) == DNS_Success) {
*subnet_bits = ip->family == IPADDR_INET6 ? 128 : 32;
return 1;
}
return 0;
}
/* ================================================== */
CPS_Status
CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance, double *activate,
double *wait_synced, double *wait_unsynced)
{
int n;
char *cmd;
*stratum = 10;
*distance = 1.0;
*activate = 0.0;
*orphan = 0;
*wait_synced = 0;
*wait_unsynced = -1.0;
while (*line) {
cmd = line;
line = CPS_SplitWord(line);
if (!strcasecmp(cmd, "stratum")) {
if (!SSCANF_IN_RANGE(line, "%d%n", stratum, &n, 1, NTP_MAX_STRATUM - 1))
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "orphan")) {
*orphan = 1;
n = 0;
} else if (!strcasecmp(cmd, "distance")) {
if (sscanf(line, "%lf%n", distance, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "activate")) {
if (sscanf(line, "%lf%n", activate, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "waitsynced")) {
if (sscanf(line, "%lf%n", wait_synced, &n) != 1)
return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "waitunsynced")) {
if (sscanf(line, "%lf%n", wait_unsynced, &n) != 1)
return CPS_InvalidValue;
} else {
return CPS_InvalidOption;
}
line += n;
}
if (*wait_unsynced < 0.0)
*wait_unsynced = *orphan ? 300 : 0.0;
return CPS_Success;
return result;
}
/* ================================================== */
@@ -413,7 +254,7 @@ CPS_SplitWord(char *line)
/* ================================================== */
int
CPS_ParseKey(char *line, uint32_t *id, const char **type, char **key)
CPS_ParseKey(char *line, unsigned long *id, const char **hash, char **key)
{
char *s1, *s2, *s3, *s4;
@@ -426,32 +267,16 @@ CPS_ParseKey(char *line, uint32_t *id, const char **type, char **key)
if (!*s2 || *s4)
return 0;
if (sscanf(s1, "%"SCNu32, id) != 1)
if (sscanf(s1, "%lu", id) != 1)
return 0;
if (*s3) {
*type = s2;
*hash = s2;
*key = s3;
} else {
*type = "MD5";
*hash = "MD5";
*key = s2;
}
return 1;
}
/* ================================================== */
int
CPS_ParseRefid(char *line, uint32_t *ref_id)
{
int i;
for (i = *ref_id = 0; line[i] && !isspace((unsigned char)line[i]); i++) {
if (i >= 4)
return 0;
*ref_id |= (uint32_t)line[i] << (24 - i * 8);
}
return i;
}

View File

@@ -32,31 +32,29 @@
typedef enum {
CPS_Success,
CPS_InvalidValue,
CPS_InvalidOption,
CPS_MissingArgument,
CPS_BadOption,
CPS_BadHost,
CPS_BadPort,
CPS_BadMinpoll,
CPS_BadMaxpoll,
CPS_BadPresend,
CPS_BadMaxdelaydevratio,
CPS_BadMaxdelayratio,
CPS_BadMaxdelay,
CPS_BadKey,
CPS_BadMinstratum,
CPS_BadPolltarget
} CPS_Status;
typedef struct {
char *name;
int family;
int port;
unsigned short port;
SourceParameters params;
} CPS_NTP_Source;
/* Parse a command to add an NTP server or peer */
extern CPS_Status CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
/* Get an NTP/refclock select option */
extern int CPS_GetSelectOption(char *option);
/* Parse a command to allow/deny access */
extern int CPS_ParseAllowDeny(char *line, int *all, IPAddr *ip, int *subnet_bits);
/* Parse a command to enable local reference */
extern CPS_Status CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance,
double *activate, double *wait_synced, double *wait_unsynced);
/* Remove extra white-space and comments */
extern void CPS_NormalizeLine(char *line);
@@ -64,9 +62,6 @@ extern void CPS_NormalizeLine(char *line);
extern char *CPS_SplitWord(char *line);
/* Parse a key from keyfile */
extern int CPS_ParseKey(char *line, uint32_t *id, const char **type, char **key);
/* Parse a refclock reference ID (returns number of characters) */
extern int CPS_ParseRefid(char *line, uint32_t *ref_id);
extern int CPS_ParseKey(char *line, unsigned long *id, const char **hash, char **key);
#endif /* GOT_CMDPARSE_H */

2123
conf.c

File diff suppressed because it is too large Load Diff

93
conf.h
View File

@@ -29,39 +29,26 @@
#define GOT_CONF_H
#include "addressing.h"
#include "array.h"
#include "reference.h"
#include "sources.h"
extern void CNF_Initialise(int restarted, int client_only);
extern void CNF_Finalise(void);
extern void CNF_EnablePrint(void);
extern void CNF_SetRestarted(int);
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_CheckReadOnlyAccess(void);
extern void CNF_AddInitSources(void);
extern void CNF_AddSources(void);
extern void CNF_AddBroadcasts(void);
extern void CNF_AddRefclocks(void);
extern void CNF_ReloadSources(void);
extern int CNF_GetAcquisitionPort(void);
extern int CNF_GetNTPPort(void);
extern char *CNF_GetDriftFile(int *interval);
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_GetLogSelection(void);
extern int CNF_GetLogMeasurements(void);
extern int CNF_GetLogStatistics(void);
extern int CNF_GetLogTracking(void);
extern int CNF_GetLogRtc(void);
@@ -69,14 +56,16 @@ extern int CNF_GetLogRefclocks(void);
extern int CNF_GetLogTempComp(void);
extern char *CNF_GetKeysFile(void);
extern char *CNF_GetRtcFile(void);
extern unsigned long CNF_GetCommandKey(void);
extern int CNF_GetGenerateCommandKey(void);
extern int CNF_GetDumpOnExit(void);
extern int CNF_GetManualEnabled(void);
extern ARR_Instance CNF_GetOpenCommands(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_GetLogChange(int *enabled, double *threshold);
extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user);
extern int CNF_GetNoClientLog(void);
extern unsigned long CNF_GetClientLogLimit(void);
@@ -84,101 +73,37 @@ 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_GetBindNtpInterface(void);
extern char *CNF_GetBindAcquisitionInterface(void);
extern char *CNF_GetBindCommandInterface(void);
extern char *CNF_GetBindCommandPath(void);
extern int CNF_GetNtpDscp(void);
extern char *CNF_GetNtpSigndSocket(void);
extern char *CNF_GetPidFile(void);
extern REF_LeapMode CNF_GetLeapSecMode(void);
extern char *CNF_GetLeapSecTimezone(void);
extern char *CNF_GetLeapSecList(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_GetClockPrecision(void);
extern SRC_AuthSelectMode CNF_GetAuthSelectMode(void);
extern double CNF_GetMaxDistance(void);
extern double CNF_GetMaxJitter(void);
extern int CNF_GetMaxStratum(void);
extern int CNF_GetMinStratum(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, double *activate,
double *wait_synced, double *wait_unsynced);
extern int CNF_AllowLocalReference(int *stratum);
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, int *kod);
extern int CNF_GetNtsRateLimit(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 void CNF_GetTempComp(char **file, double *interval, double *T0, double *k0, double *k1, double *k2);
extern char *CNF_GetUser(void);
extern int CNF_GetMaxSamples(void);
extern int CNF_GetMinSamples(void);
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_PTP,
CNF_HWTS_RXFILTER_ALL,
} CNF_HwTs_RxFilter;
typedef struct {
char *name;
int minpoll;
int maxpoll;
int min_samples;
int max_samples;
int nocrossts;
CNF_HwTs_RxFilter rxfilter;
double precision;
double tx_comp;
double rx_comp;
} CNF_HwTsInterface;
extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
extern double CNF_GetHwTsTimeout(void);
extern int CNF_GetPtpPort(void);
extern int CNF_GetPtpDomain(void);
extern int CNF_GetRefresh(void);
extern ARR_Instance CNF_GetNtsAeads(void);
extern char *CNF_GetNtsDumpDir(void);
extern char *CNF_GetNtsNtpServer(void);
extern int CNF_GetNtsServerCertAndKeyFiles(const char ***certs, const char ***keys);
extern int CNF_GetNtsServerPort(void);
extern int CNF_GetNtsServerProcesses(void);
extern int CNF_GetNtsServerConnections(void);
extern int CNF_GetNtsRefresh(void);
extern int CNF_GetNtsRotate(void);
extern int CNF_GetNtsTrustedCertsPaths(const char ***paths, uint32_t **ids);
extern int CNF_GetNoSystemCert(void);
extern int CNF_GetNoCertTimeCheck(void);
#endif /* GOT_CONF_H */

885
configure vendored

File diff suppressed because it is too large Load Diff

339
contrib/DNSchrony/COPYING Normal file
View File

@@ -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.

583
contrib/DNSchrony/DNSchrony.pl Executable file
View File

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

21
contrib/DNSchrony/DNSchronyADD Executable file
View File

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

View File

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

View File

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

166
contrib/DNSchrony/README Normal file
View File

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

View File

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

View File

@@ -1,103 +0,0 @@
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.chrony-project.chronyc.plist
-rw-r--r-- 1 yourname staff 511 19 Jun 18:30 org.chrony-project.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.chrony-project.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.chrony-project.chronyc.plist /Library/LaunchDaemons
sudo chown root:wheel /Library/LaunchDaemons/org.chrony-project.chronyc.plist
sudo chmod 0644 /Library/LaunchDaemons/org.chrony-project.chronyc.plist
sudo launchctl load -w /Library/LaunchDaemons/org.chrony-project.chronyc.plist
3. org.chrony-project.chronyd.plist
This file is the launchd plist that runs chronyd when the Macintosh starts.
sudo cp org.chrony-project.chronyd.plist /Library/LaunchDaemons
sudo chown root:wheel /Library/LaunchDaemons/org.chrony-project.chronyd.plist
sudo chmod 0644 /Library/LaunchDaemons/org.chrony-project.chronyd.plist
sudo launchctl load -w /Library/LaunchDaemons/org.chrony-project.chronyd.plist

View File

@@ -1,58 +0,0 @@
#!/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 $?

View File

@@ -1,22 +0,0 @@
<?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.chrony-project.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>

View File

@@ -1,19 +0,0 @@
<?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.chrony-project.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>

View File

@@ -1,78 +0,0 @@
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_CHRONYC_USER = @DEFAULT_CHRONYC_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%\@DEFAULT_CHRONYC_USER\@%$(DEFAULT_CHRONYC_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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,243 +0,0 @@
// 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_.
Informational messages, warnings, and errors 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. The compiled-in default value is _@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. If
*chronyd* was compiled with enabled support for debugging, this option can be
used twice to enable debug messages.
*-l* _file_::
This option enables writing of log messages to a file instead of syslog or the
terminal.
*-L* _level_::
This option specifies the minimum severity level of messages to be written to
the log file, syslog, or terminal. The following levels can be specified: -1
(debug, if compiled with enabled support for debugging), 0 (informational), 1
(warning), 2 (non-fatal error), and 3 (fatal error). The default value is 0.
*-p*::
When run in this mode, *chronyd* will print the configuration and exit. It will
not detach from the terminal. This option can be used to verify the syntax of
the configuration and get the whole configuration, even if it is split into
multiple files and read by the *include* or *confdir* directive.
*-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 disables server ports to allow
*chronyd* to be started without root privileges, assuming the configuration
does not have any directives which would require them (e.g. *refclock*,
*hwtimestamp*, *rtcfile*, etc).
*-r*::
This option will try to reload and then delete files containing sample
histories for each of the servers and reference clocks being used. The
files are expected to be in the directory specified by the
<<chrony.conf.adoc#dumpdir,*dumpdir*>>
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,
illumos, 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. The compiled-in default value is
_@DEFAULT_USER@_.
+
On Linux, *chronyd* needs to be compiled with support for the *libcap* library.
On macOS, FreeBSD, NetBSD, and illumos *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.
*-U*::
This option disables a check for root privileges to allow *chronyd* to be
started under a non-root user, assuming the process will have all capabilities
(e.g. provided by the service manager) and access to all files, directories,
and devices, needed to operate correctly in the specified configuration. Note
that different capabilities might be needed with different configurations and
different Linux kernel versions. Starting *chronyd* under a non-root user is
not recommended when the configuration is not known, or at least limited to
specific directives.
*-F* _level_::
This option configures system call filters loaded by *chronyd* processes if it
was compiled with support for the Linux secure computing (seccomp) facility.
Three levels are defined: 0, 1, 2. The filters are disabled at level 0. At
levels 1 and 2, *chronyd* will be killed if it makes a system call which is
blocked by the filters. The level can be specified as a negative number to
trigger the SIGSYS signal instead of SIGKILL, which can be useful for
debugging. The default value is 0.
+
At level 1, the filters allow only selected system calls that are normally
expected to be made by *chronyd*. Other system calls are blocked. This level is
recommended only if it is known to work on the version of the system where
*chrony* is installed. The filters need to allow also system calls made by
libraries that *chronyd* is using (e.g. libc), but different versions or
implementations of the libraries might make different system calls. If the
filters are missing a system call, *chronyd* could be killed even in normal
operation.
+
At level 2, the filters block only a small number of specific system calls
(e.g. fork and exec). This approach should avoid false positives, but the
protection of the system against a compromised *chronyd* process is much more
limited.
+
The filters cannot be enabled with the *mailonchange* directive.
*-P* _priority_::
On Linux, FreeBSD, NetBSD, and illumos 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 to disable the thread
time constraint policy or 1 for the policy to be enabled. Other systems do not
support this option. The default value is 0.
*-m*::
This option will lock *chronyd* into RAM so that it will never be paged out.
This mode is only supported on Linux, FreeBSD, NetBSD, and illumos.
*-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 be started without the capability to adjust or set
the system clock (e.g. in some containers) to operate as an NTP server.
*-v*, *--version*::
With this option *chronyd* will print version number to the terminal and exit.
*-h*, *--help*::
With this option *chronyd* will print a help message to the terminal and exit.
== ENVIRONMENT VARIABLES
*LISTEN_FDS*::
On Linux systems, the systemd service manager may pass file descriptors for
pre-initialised sockets to *chronyd*. The service manager allocates and binds
the file descriptors, and passes a copy to each spawned instance of the
service. This allows for zero-downtime service restarts as the sockets buffer
client requests until the service is able to handle them. The service manager
sets the LISTEN_FDS environment variable to the number of passed file
descriptors.
*NOTIFY_SOCKET*::
The systemd service manager sets this variable for services of the *notify*
type. *chronyd* sends a message to this socket when it it is fully initialised
and ready to accept commands (e.g. from *chronyc*), with the clock already set
if using the *-s* option or *initstepslew* directive. It is an alternative to
the *forking* service type, which does not need the PID file. *chronyd* needs
to be started with the *-n* or *-d* option to not fork.
== 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-project.org/.
== AUTHORS
chrony was written by Richard Curnow, Miroslav Lichvar, and others.

View File

@@ -1,74 +0,0 @@
// This file is part of chrony
//
// Copyright (C) Miroslav Lichvar 2024
//
// 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.
= Contributing
== Patches
The source code of `chrony` is maintained in a git repository at
https://gitlab.com/chrony/chrony. Patches can be submitted to the `chrony-dev`
mailing list, or as a merge request on gitlab. Before spending a lot of time
implementing a new major feature, it is recommended to ask on the mailing list
for comments about its design and whether such feature fits the goals of the
project.
Each commit should be a self-contained logical change, which does not break
the build or tests. New functionality and fixed bugs should be covered by a new
test or an extended existing test in the test suite. The test can be included
in the same commit or added as a separate commit. The same rule applies to
documentation. All command-line options, configuration directives, and
`chronyc` commands should be documented.
The most important tests can be executed by running `make check` or `make
quickcheck`. The unit and system tests run on all supported systems. The system
tests require root privileges. The simulation tests run only on Linux and
require https://gitlab.com/chrony/clknetsim[clknetsim] to be compiled in the
directory containing the tests, but they are executed with a merge request on
gitlab.
The commit message should explain any non-trivial changes, e.g. what problem is
the commit solving and how. The commit subject (first line of the message)
should be written in an imperative form, prefixed with the component name if it
is not a more general change, starting in lower case, and no period at the end.
See the git log for examples.
Simpler code is better. Less code is better. Security is a top priority.
Assertions should catch only bugs in the `chrony` code. Unexpected values in
external input (e.g. anything received from network) must be handled correctly
without crashing and memory corruption. Fuzzing support is available at
https://gitlab.com/chrony/chrony-fuzz. The fuzzing coverage is checked by the
project maintainer before each release.
The code should mostly be self-documenting. Comments should explain the
less obvious things.
== Coding style
The code uses two spaces for indentation. No tabs. The line length should
normally not exceed 95 characters. Too much indentation indicates the code will
not be very readable.
Function names are in an imperative form. Names of static functions use
lowercase characters and underscores. Public functions, structures, typedefs
are in CamelCase with a prefix specific to the module (e.g. LCL - local, NCR
- NTP core, NKS - NTS-KE server, SST - sourcestats).
Function names are not followed by space, but keywords of the language (e.g.
`if`, `for`, `while`, `sizeof`) are followed by space.
Have a look at the existing code to get a better idea what is expected.

File diff suppressed because it is too large Load Diff

View File

@@ -1,193 +0,0 @@
// 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.
A C compiler (e.g. `gcc` or `clang`) and GNU Make are needed to build `chrony`.
The following libraries with their development files, and programs, are needed
to enable optional features:
* pkg-config: detection of development libraries
* Nettle, GnuTLS, NSS, or LibTomCrypt: secure hash functions (`SECHASH`)
* libcap: dropping root privileges on Linux (`DROPROOT`)
* libseccomp: system call filter on Linux (`SCFILTER`)
* GnuTLS and Nettle: Network Time Security (`NTS`)
* Editline: line editing in `chronyc` (`READLINE`)
* timepps.h header: PPS reference clock
* Asciidoctor: documentation in HTML format
* Bash: test suite
The following programs are needed when building `chrony` from the git
repository instead of a released tar file:
* Asciidoctor: manual pages
* Bison: parser for chronyc settime command
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 https://www.lysator.liu.se/~nisse/nettle/[Nettle],
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS[NSS], or
https://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 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.
== 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.

View File

@@ -1,6 +1,5 @@
[Unit]
Description=Wait for chrony to synchronize system clock
Documentation=man:chronyc(1)
After=chronyd.service
Requires=chronyd.service
Before=time-sync.target
@@ -8,39 +7,11 @@ Wants=time-sync.target
[Service]
Type=oneshot
# Wait for chronyd to update the clock and the remaining
# correction to be less than 0.1 seconds
ExecStart=/usr/bin/chronyc -h 127.0.0.1,::1 waitsync 0 0.1 0.0 1
# Wait for at most 3 minutes
TimeoutStartSec=180
# 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 waitsync 60 0.1
RemainAfterExit=yes
StandardOutput=null
CapabilityBoundingSet=
DevicePolicy=closed
DynamicUser=yes
IPAddressAllow=localhost
IPAddressDeny=any
LockPersonality=yes
MemoryDenyWriteExecute=yes
PrivateDevices=yes
PrivateUsers=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectProc=invisible
ProtectSystem=strict
RestrictAddressFamilies=AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources
UMask=0777
[Install]
WantedBy=multi-user.target

View File

@@ -5,6 +5,22 @@
# want to enable. The more obscure options are not included. Refer
# to the documentation for these.
#
# Copyright 2002 Richard P. Curnow
#
# 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.
#
#
#######################################################################
### COMMENTS
# Any of the following lines are comments (you have a choice of
@@ -21,58 +37,50 @@
#######################################################################
### SPECIFY YOUR NTP SERVERS
# Most computers using chrony will send measurement requests to one or
# more NTP servers. The general recommendation is to have at least
# three NTP servers to be able to detect one server providing incorrect
# time (falseticker). You will probably find that your Internet Service
# 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 https://support.ntp.org/bin/view/Servers/WebHome or
# you can access at http://support.ntp.org/bin/view/Servers/WebHome or
# you can use servers from the pool.ntp.org project.
! server ntp1.example.net iburst
! server ntp2.example.net iburst
! server ntp3.example.net iburst
! pool pool.ntp.org iburst
! server 0.pool.ntp.org iburst
! server 1.pool.ntp.org iburst
! server 2.pool.ntp.org iburst
# However, for dial-up use you probably want these instead. The word
# 'offline' means that the server is not visible at boot time. Use
# chronyc's 'online' command to tell chronyd that these servers have
# become visible after you go on-line.
! server 0.pool.ntp.org offline
! server 1.pool.ntp.org offline
! server 2.pool.ntp.org offline
# You may want to specify NTP 'peers' instead. If you run a network
# with a lot of computers and want several computers running chrony to
# have the 'front-line' interface to the public NTP servers, you can
# 'peer' these machines together to increase robustness.
! peer ntp0.my-company.com
# There are other options to the 'server' and 'peer' directives that you
# might want to use. For example, you can ignore measurements whose
# round-trip-time is too large (indicating that the measurement is
# probably useless, because you don't know which way the measurement
# message got held up.) Consult the full documentation for details.
#######################################################################
### 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.
# one of the following lines. The first seems good for dial-up (or
# other high-latency connections like slow leased lines), 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
# By default, chronyd allows synchronisation to an unauthenticated NTP
# source (i.e. specified without the nts and key options) if it agrees with
# a majority of authenticated NTP sources, or if no authenticated source is
# specified. If you don't want chronyd to ever synchronise to an
# unauthenticated NTP source, uncomment the first from the following lines.
# If you don't want to synchronise to an unauthenticated NTP source only
# when an authenticated source is specified, uncomment the second line.
# If you want chronyd to ignore authentication in the source selection,
# uncomment the third line.
! authselectmode require
! authselectmode prefer
! authselectmode ignore
#######################################################################
### FILENAMES ETC
# Chrony likes to keep information about your computer's clock in files.
@@ -83,42 +91,40 @@
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.
# If you want to use the program called chronyc to configure aspects of
# chronyd's operation once it is running (e.g. tell it the Internet link
# has gone up or down), you need a password. This is stored in the
# following keys file. (You also need keys to support authenticated NTP
# exchanges between cooperating machines.) Again, this option is
# assumed by default.
! keyfile /etc/chrony.keys
keyfile /etc/chrony.keys
# If you specify an NTP server with the nts option to enable authentication
# with the Network Time Security (NTS) mechanism, or enable server NTS with
# the ntsservercert and ntsserverkey directives below, the following line will
# allow the client/server to save the NTS keys and cookies in order to reduce
# the number of key establishments (NTS-KE sessions).
# Tell chronyd which numbered key in the file is used as the password
# for chronyc. (You can pick any integer up to 2**32-1. '1' is just a
# default. Using another value will _NOT_ increase security.)
ntsdumpdir /var/lib/chrony
commandkey 1
# If chronyd is configured to act as an NTP server and you want to enable NTS
# for its clients, you will need a TLS certificate and private key. Uncomment
# and edit the following lines to specify the locations of the certificate and
# key.
! ntsservercert /etc/.../nts-server.crt
! ntsserverkey /etc/.../nts-server.key
# With this directive a random password will be generated automatically.
generatecommandkey
# chronyd can save the measurement history for the servers to files when
# it exits. This is useful in 2 situations:
# it it exits. This is useful in 2 situations:
#
# 1. If you stop chronyd and restart it with the '-r' option (e.g. after
# 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.
# gain/loss measurements, especially with a dial-up link.
#
# 2. On Linux, if you use the RTC support and start chronyd with
# 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).
#
# Uncomment the following line to use this.
# 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
@@ -126,38 +132,20 @@ ntsdumpdir /var/lib/chrony
# 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/chrony/chronyd.pid
# The system timezone database usually comes with a list of leap seconds and
# corresponding TAI-UTC offsets. chronyd can use it to set the offset of the
# system TAI clock and have an additional source of leap seconds.
! leapseclist /usr/share/zoneinfo/leap-seconds.list
! pidfile /var/run/chronyd.pid
#######################################################################
### 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
# off by a large amount. The value '10' means that if the error is less
# than 10 seconds, it will be gradually removed by speeding up or
# slowing down your computer's clock until it is correct. If the error
# is above 10 seconds, an immediate time jump will be applied to correct
# it. The value '1' means the step is allowed only on the first update
# of the clock. Some software can get upset if the system clock jumps
# (especially backwards), so be careful!
! makestep 1.0 3
#######################################################################
### LEAP SECONDS
# A leap second is an occasional one-second correction of the UTC
# time scale. By default, chronyd tells the kernel to insert/delete
# the leap second, which makes a backward/forward step to correct the
# clock for it. As with the makestep directive, this jump can upset
# some applications. If you prefer chronyd to make a gradual
# correction, causing the clock to be off for a longer time, uncomment
# the following line.
! leapsecmode slew
! makestep 10 1
#######################################################################
### LOGGING
@@ -178,6 +166,8 @@ ntsdumpdir /var/lib/chrony
#######################################################################
### 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.
@@ -193,6 +183,15 @@ ntsdumpdir /var/lib/chrony
# 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
@@ -207,22 +206,16 @@ ntsdumpdir /var/lib/chrony
# 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.
# clients.
! noclientlog
# The clientlog size is limited to 512KB by default. If you have many
# clients, you might want to increase the limit.
# clients, especially in many different subnets, 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
@@ -240,19 +233,13 @@ ntsdumpdir /var/lib/chrony
# several people, you need to set up a mailing list or sendmail alias
# for them and use the address of that.)
! mailonchange wibble@example.net 0.5
! mailonchange wibble@foobar.org 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
@@ -265,20 +252,10 @@ ntsdumpdir /var/lib/chrony
# 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 *
# NOTE, even if the host where you run chronyc is granted access, you
# still need a command key set up and you have to know the password to
# put into chronyc to allow you to modify chronyd's parameters. By
# default all you can do is view information about chronyd's operation.
#######################################################################
### REAL TIME CLOCK
@@ -309,12 +286,6 @@ ntsdumpdir /var/lib/chrony
! 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

View File

@@ -1,12 +0,0 @@
# Use four 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

View File

@@ -1,52 +1,46 @@
# Note: The general recommendation for an NTP client is to have at least
# three NTP servers to be able to detect one server providing incorrect
# time (falseticker).
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
server 0.pool.ntp.org iburst
server 1.pool.ntp.org iburst
server 2.pool.ntp.org iburst
server 3.pool.ntp.org iburst
# Use four public NTP servers from the pool.ntp.org project. If this
# host has a static public IP address, please consider joining the pool:
# https://www.ntppool.org/join.html
pool pool.ntp.org iburst
# Ignore stratum in source selection.
stratumweight 0
# 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).
# Enable kernel RTC synchronization.
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
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 10 seconds.
makestep 10 3
# Allow NTP client access from local network.
#allow 192.168.0.0/16
#allow 192.168/16
# Serve time even if not synchronized to a time source.
# Listen for commands only on localhost.
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
# Serve time even if not synchronized to any NTP server.
#local stratum 10
# Require authentication (nts or key option) for all NTP sources.
#authselectmode require
keyfile /etc/chrony.keys
# Specify file containing keys for NTP authentication.
#keyfile /etc/chrony.keys
# Specify the key used as password for chronyc.
commandkey 1
# Save NTS keys and cookies.
ntsdumpdir /var/lib/chrony
# Generate command key if missing.
generatecommandkey
# Insert/delete leap seconds by slewing instead of stepping.
#leapsecmode slew
# Disable logging of client accesses.
noclientlog
# Set the TAI-UTC offset of the system clock.
#leapseclist /usr/share/zoneinfo/leap-seconds.list
# Send a message to syslog if a clock adjustment is larger than 0.5 seconds.
logchange 0.5
# Specify directory for log files.
logdir /var/log/chrony
# Select which information is logged.
#log measurements statistics tracking

View File

@@ -1,15 +1,29 @@
# This is an example chrony keys file. It enables authentication of NTP
# packets with symmetric keys when its location is specified by the keyfile
# directive in chrony.conf(5). It should be readable only by root and the
# user under which chronyd is running.
#######################################################################
#
# Don't use the example keys! It's recommended to generate random keys using
# the chronyc keygen command.
# This is an example chrony keys file. You should copy it to /etc/chrony.keys
# after editing it to set up the key(s) you want to use. It should be readable
# only by root or the user chronyd drops the root privileges to. In most
# situations, you will require a single key (the 'commandkey') so that you can
# supply a password to chronyc to enable you to modify chronyd's operation
# whilst it is running.
#
# Copyright 2002 Richard P. Curnow
#
######################################################################
# Examples of valid keys:
#1 MD5 AVeryLongAndRandomPassword
#2 MD5 HEX:12114855C7931009B4049EF3EFC48A139C3F989F
#3 SHA1 HEX:B2159C05D6A219673A3B7E896B6DE07F6A440995
#4 AES128 HEX:2DA837C4B6573748CA692B8C828E4891
#5 AES256 HEX:2666B8099BFF2D5BA20876121788ED24D2BE59111B8FFB562F0F56AE6EC7246E
#1 ALongAndRandomPassword
#2 MD5 HEX:B028F91EA5C38D06C2E140B26C7F41EC
#3 SHA1 HEX:1DC764E0791B11FA67EFC7ECBC4B0D73F68A070C
# The keys should be random for maximum security. If you wanted to use a key
# with ID 1 as your commandkey (i.e. chronyc password) you would put
# "commandkey 1" into chrony.conf. If no commandkey is present in the keys
# file and the generatecommandkey directive is specified in chrony.conf,
# a random commandkey will be generated and added to the keys file
# automatically on chronyd start.
# You might want to define more keys if you use the authentication facility
# in the network time protocol to authenticate request/response packets between
# trusted clients and servers.

View File

@@ -3,6 +3,6 @@
nocreate
sharedscripts
postrotate
/usr/bin/chronyc cyclelogs > /dev/null 2>&1 || true
/usr/bin/chronyc -a cyclelogs > /dev/null 2>&1 || true
endscript
}

View File

@@ -0,0 +1,17 @@
#!/bin/sh
# This is a NetworkManager dispatcher script for chronyd to set its NTP sources
# online/offline when a default route is configured/removed on the system.
export LC_ALL=C
if [ "$2" = "up" ]; then
/sbin/ip route list dev "$1" | grep -q '^default' &&
/usr/bin/chronyc -a online > /dev/null 2>&1
fi
if [ "$2" = "down" ]; then
/sbin/ip route list | grep -q '^default' ||
/usr/bin/chronyc -a offline > /dev/null 2>&1
fi
exit 0

View File

@@ -1,49 +0,0 @@
#!/bin/sh
# This is a NetworkManager dispatcher script for chronyd to update
# its NTP sources with servers from DHCP options passed by NetworkManager
# in the DHCP4_NTP_SERVERS and DHCP6_DHCP6_NTP_SERVERS environment variables.
export LC_ALL=C
interface=$1
action=$2
chronyc=/usr/bin/chronyc
server_options=iburst
server_dir=/var/run/chrony-dhcp
dhcp_server_file=$server_dir/$interface.sources
dhcp_ntp_servers="$DHCP4_NTP_SERVERS $DHCP6_DHCP6_NTP_SERVERS"
add_servers_from_dhcp() {
rm -f "$dhcp_server_file"
for server in $dhcp_ntp_servers; do
# Check for invalid characters (from the DHCPv6 NTP FQDN suboption)
len1=$(printf '%s' "$server" | wc -c)
len2=$(printf '%s' "$server" | tr -d -c 'A-Za-z0-9:.-' | wc -c)
if [ "$len1" -ne "$len2" ] || [ "$len2" -lt 1 ] || [ "$len2" -gt 255 ]; then
continue
fi
printf 'server %s %s\n' "$server" "$server_options" >> "$dhcp_server_file"
done
$chronyc reload sources > /dev/null 2>&1 || :
}
clear_servers_from_dhcp() {
if [ -f "$dhcp_server_file" ]; then
rm -f "$dhcp_server_file"
$chronyc reload sources > /dev/null 2>&1 || :
fi
}
mkdir -p $server_dir
case "$action" in
up|dhcp4-change|dhcp6-change)
add_servers_from_dhcp;;
down)
clear_servers_from_dhcp;;
esac
exit 0

View File

@@ -1,29 +0,0 @@
#!/bin/sh
# This is a NetworkManager dispatcher / networkd-dispatcher script for
# chronyd to set its NTP sources online or offline when a network interface
# is configured or removed
export LC_ALL=C
chronyc=/usr/bin/chronyc
# For NetworkManager consider only selected events
if [ $# -ge 2 ]; then
case "$2" in
up|down|connectivity-change)
;;
dhcp4-change|dhcp6-change)
# Actions "up" and "connectivity-change" in some cases do not
# guarantee that the interface has a route (e.g. a bond).
# dhcp(x)-change handles at least cases that use DHCP.
;;
*)
exit 0;;
esac
fi
# Note: for networkd-dispatcher routable.d ~= on and off.d ~= off
$chronyc onoffline > /dev/null 2>&1
exit 0

57
examples/chrony.spec Normal file
View File

@@ -0,0 +1,57 @@
%global chrony_version @@VERSION@@
%if 0%(echo %{chrony_version} | grep -q pre && echo 1)
%global prerelease %(echo %{chrony_version} | sed 's/.*-//')
%endif
Summary: An NTP client/server
Name: chrony
Version: %(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)
Requires: info
%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} \
--infodir=%{_infodir} \
--mandir=%{_mandir}
make
make chrony.txt
make chrony.info
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
rm -rf $RPM_BUILD_ROOT%{_docdir}
mkdir -p $RPM_BUILD_ROOT%{_infodir}
cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
%files
%{_sbindir}/chronyd
%{_bindir}/chronyc
%{_infodir}/chrony.info*
%{_mandir}/man1/chrony.1.gz
%{_mandir}/man1/chronyc.1.gz
%{_mandir}/man5/chrony.conf.5.gz
%{_mandir}/man8/chronyd.8.gz
%doc README
%doc chrony.txt
%doc COPYING
%doc examples/chrony.conf.example*
%doc examples/chrony.keys.example

View File

@@ -1,59 +0,0 @@
# This is a more restricted version of the chronyd service intended for
# minimal NTP/NTS client configurations. The daemon is started without root
# privileges and is allowed to write only to its own runtime, state, and log
# directories. It cannot bind to privileged ports in order to operate as an
# NTP server, or provide monitoring access over IPv4/IPv6. It cannot use
# reference clocks, HW timestamping, RTC tracking, and other features.
[Unit]
Description=NTP client (restricted)
Documentation=man:chronyd(8) man:chrony.conf(5)
After=chronyd.service ntpdate.service sntp.service ntpd.service
Conflicts=chronyd.service ntpd.service systemd-timesyncd.service
ConditionCapability=CAP_SYS_TIME
[Service]
Type=notify
PIDFile=/run/chrony/chronyd.pid
Environment="OPTIONS="
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd -n -U $OPTIONS
User=chrony
LogsDirectory=chrony
LogsDirectoryMode=0750
RuntimeDirectory=chrony
RuntimeDirectoryMode=0750
RuntimeDirectoryPreserve=restart
StateDirectory=chrony
StateDirectoryMode=0750
AmbientCapabilities=CAP_SYS_TIME
CapabilityBoundingSet=CAP_SYS_TIME
DevicePolicy=closed
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
# This breaks adjtimex()
#PrivateUsers=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectProc=invisible
ProtectSystem=strict
RemoveIPC=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallFilter=~@cpu-emulation @debug @module @mount @obsolete @raw-io
SystemCallFilter=~@reboot @resources @swap
UMask=0077
[Install]
WantedBy=multi-user.target

View File

@@ -1,49 +1,13 @@
[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=notify
PIDFile=/run/chrony/chronyd.pid
Environment="OPTIONS="
Type=forking
PIDFile=/var/run/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd -n $OPTIONS
CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE
CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_KILL CAP_LEASE CAP_LINUX_IMMUTABLE
CapabilityBoundingSet=~CAP_MAC_ADMIN CAP_MAC_OVERRIDE CAP_MKNOD CAP_SYS_ADMIN
CapabilityBoundingSet=~CAP_SYS_BOOT CAP_SYS_CHROOT CAP_SYS_MODULE CAP_SYS_PACCT
CapabilityBoundingSet=~CAP_SYS_PTRACE CAP_SYS_RAWIO CAP_SYS_TTY_CONFIG CAP_WAKE_ALARM
DeviceAllow=char-pps rw
DeviceAllow=char-ptp rw
DeviceAllow=char-rtc rw
DevicePolicy=closed
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
PrivateTmp=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectProc=invisible
ProtectSystem=strict
ReadWritePaths=/run /var/lib/chrony -/var/log
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallFilter=~@cpu-emulation @debug @module @mount @obsolete @raw-io @reboot @swap
# Adjust restrictions for /usr/sbin/sendmail (mailonchange directive)
NoNewPrivileges=no
ReadWritePaths=-/var/spool
RestrictAddressFamilies=AF_NETLINK
ExecStart=/usr/sbin/chronyd $OPTIONS
[Install]
WantedBy=multi-user.target

2870
getdate.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,12 @@
** This code is in the public domain and has no copyright.
*/
#include "config.h"
#ifdef HAVE_CONFIG_H
# include <config.h>
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# endif
#endif
/* 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
@@ -448,9 +453,9 @@ o_merid : /* NULL */
the same signature as the function definition does. */
#include "getdate.h"
extern struct tm *gmtime (const time_t *timep);
extern struct tm *localtime (const time_t *timep);
extern time_t mktime (struct tm *tm);
extern struct tm *gmtime ();
extern struct tm *localtime ();
extern time_t mktime ();
/* Month and day table. */
static TABLE const MonthDayTable[] = {
@@ -641,13 +646,16 @@ static TABLE const MilitaryTable[] = {
/* ARGSUSED */
static int
yyerror (char *s ATTRIBUTE_UNUSED)
yyerror (s)
char *s ATTRIBUTE_UNUSED;
{
return 0;
}
static int
ToHour (int Hours, MERIDIAN Meridian)
ToHour (Hours, Meridian)
int Hours;
MERIDIAN Meridian;
{
switch (Meridian)
{
@@ -674,7 +682,8 @@ ToHour (int Hours, MERIDIAN Meridian)
}
static int
ToYear (int Year)
ToYear (Year)
int Year;
{
if (Year < 0)
Year = -Year;
@@ -690,7 +699,8 @@ ToYear (int Year)
}
static int
LookupWord (char *buff)
LookupWord (buff)
char *buff;
{
register char *p;
register char *q;
@@ -907,7 +917,6 @@ get_date (const char *p, const time_t *now)
yyHour = tmp->tm_hour;
yyMinutes = tmp->tm_min;
yySeconds = tmp->tm_sec;
memset(&tm, 0, sizeof (tm));
tm.tm_isdst = tmp->tm_isdst;
yyMeridian = MER24;
yyRelSeconds = 0;

26
hash.h
View File

@@ -31,27 +31,11 @@
/* length of hash values produced by SHA512 */
#define MAX_HASH_LENGTH 64
typedef enum {
HSH_INVALID = 0,
HSH_MD5 = 1,
HSH_SHA1 = 2,
HSH_SHA256 = 3,
HSH_SHA384 = 4,
HSH_SHA512 = 5,
HSH_SHA3_224 = 6,
HSH_SHA3_256 = 7,
HSH_SHA3_384 = 8,
HSH_SHA3_512 = 9,
HSH_TIGER = 10,
HSH_WHIRLPOOL = 11,
HSH_MD5_NONCRYPTO = 10000, /* For NTPv4 reference ID */
} HSH_Algorithm;
extern int HSH_GetHashId(const char *name);
extern int HSH_GetHashId(HSH_Algorithm algorithm);
extern int HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len);
extern void HSH_Finalise(void);
extern unsigned int HSH_Hash(int id,
const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len);
#endif

View File

@@ -1,145 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2021
*
* 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.
*
**********************************************************************
=======================================================================
Crypto hashing using the GnuTLS library
*/
#include "config.h"
#include "sysincl.h"
#include <gnutls/crypto.h>
#include "hash.h"
#include "logging.h"
struct hash {
const HSH_Algorithm algorithm;
const gnutls_digest_algorithm_t type;
gnutls_hash_hd_t handle;
};
static struct hash hashes[] = {
{ HSH_MD5_NONCRYPTO, GNUTLS_DIG_MD5, NULL },
{ HSH_MD5, GNUTLS_DIG_MD5, NULL },
{ HSH_SHA1, GNUTLS_DIG_SHA1, NULL },
{ HSH_SHA256, GNUTLS_DIG_SHA256, NULL },
{ HSH_SHA384, GNUTLS_DIG_SHA384, NULL },
{ HSH_SHA512, GNUTLS_DIG_SHA512, NULL },
{ HSH_SHA3_224, GNUTLS_DIG_SHA3_224, NULL },
{ HSH_SHA3_256, GNUTLS_DIG_SHA3_256, NULL },
{ HSH_SHA3_384, GNUTLS_DIG_SHA3_384, NULL },
{ HSH_SHA3_512, GNUTLS_DIG_SHA3_512, NULL },
{ 0, 0, NULL }
};
static int gnutls_initialised = 0;
int
HSH_GetHashId(HSH_Algorithm algorithm)
{
int id, r;
if (!gnutls_initialised) {
r = gnutls_global_init();
if (r < 0)
LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
gnutls_initialised = 1;
}
for (id = 0; hashes[id].algorithm != 0; id++) {
if (hashes[id].algorithm == algorithm)
break;
}
if (hashes[id].algorithm == 0)
return -1;
if (hashes[id].handle)
return id;
if (algorithm == HSH_MD5_NONCRYPTO)
GNUTLS_FIPS140_SET_LAX_MODE();
r = gnutls_hash_init(&hashes[id].handle, hashes[id].type);
if (algorithm == HSH_MD5_NONCRYPTO)
GNUTLS_FIPS140_SET_STRICT_MODE();
if (r < 0) {
DEBUG_LOG("Could not initialise %s : %s", "hash", gnutls_strerror(r));
hashes[id].handle = NULL;
return -1;
}
return id;
}
int
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len)
{
unsigned char buf[MAX_HASH_LENGTH];
gnutls_hash_hd_t handle;
int hash_len;
if (in1_len < 0 || in2_len < 0 || out_len < 0)
return 0;
handle = hashes[id].handle;
hash_len = gnutls_hash_get_len(hashes[id].type);
if (out_len > hash_len)
out_len = hash_len;
if (hash_len > sizeof (buf))
return 0;
if (gnutls_hash(handle, in1, in1_len) < 0 ||
(in2 && gnutls_hash(handle, in2, in2_len) < 0)) {
/* Reset the state */
gnutls_hash_output(handle, buf);
return 0;
}
gnutls_hash_output(handle, buf);
memcpy(out, buf, out_len);
return out_len;
}
void
HSH_Finalise(void)
{
int i;
if (!gnutls_initialised)
return;
for (i = 0; hashes[i].algorithm != 0; i++) {
if (hashes[i].handle)
gnutls_hash_deinit(hashes[i].handle, NULL);
}
gnutls_global_deinit();
}

View File

@@ -29,27 +29,27 @@
#include "sysincl.h"
#include "hash.h"
#include "memory.h"
#include "util.h"
#include "md5.c"
static MD5_CTX ctx;
int
HSH_GetHashId(HSH_Algorithm algorithm)
HSH_GetHashId(const char *name)
{
/* only MD5 is supported */
if (algorithm != HSH_MD5 && algorithm != HSH_MD5_NONCRYPTO)
if (strcmp(name, "MD5"))
return -1;
return 0;
}
int
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len)
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 (in1_len < 0 || in2_len < 0 || out_len < 0)
if (out_len < 16)
return 0;
MD5Init(&ctx);
@@ -58,14 +58,7 @@ HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
MD5Update(&ctx, in2, in2_len);
MD5Final(&ctx);
out_len = MIN(out_len, 16);
memcpy(out, ctx.digest, 16);
memcpy(out, ctx.digest, out_len);
return out_len;
}
void
HSH_Finalise(void)
{
return 16;
}

View File

@@ -1,124 +0,0 @@
/*
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 HSH_Algorithm algorithm;
const char *int_name;
const struct nettle_hash *nettle_hash;
void *context;
};
static struct hash hashes[] = {
{ HSH_MD5, "md5", NULL, NULL },
{ HSH_SHA1, "sha1", NULL, NULL },
{ HSH_SHA256, "sha256", NULL, NULL },
{ HSH_SHA384, "sha384", NULL, NULL },
{ HSH_SHA512, "sha512", NULL, NULL },
{ HSH_SHA3_224, "sha3_224", NULL, NULL },
{ HSH_SHA3_256, "sha3_256", NULL, NULL },
{ HSH_SHA3_384, "sha3_384", NULL, NULL },
{ HSH_SHA3_512, "sha3_512", NULL, NULL },
{ 0, NULL, NULL, NULL }
};
int
HSH_GetHashId(HSH_Algorithm algorithm)
{
int id, nid;
if (algorithm == HSH_MD5_NONCRYPTO)
algorithm = HSH_MD5;
for (id = 0; hashes[id].algorithm != 0; id++) {
if (hashes[id].algorithm == algorithm)
break;
}
if (hashes[id].algorithm == 0)
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;
}
int
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len)
{
const struct nettle_hash *hash;
void *context;
if (in1_len < 0 || in2_len < 0 || out_len < 0)
return 0;
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].algorithm != 0; i++) {
if (hashes[i].context)
Free(hashes[i].context);
}
}

View File

@@ -25,46 +25,41 @@
*/
#include "config.h"
#include <nss.h>
#include <hasht.h>
#include <nsslowhash.h>
/* #include "config.h" */
#include "hash.h"
#include "util.h"
static NSSLOWInitContext *ictx;
struct hash {
HASH_HashType type;
HSH_Algorithm algorithm;
const char *name;
NSSLOWHASHContext *context;
};
static struct hash hashes[] = {
{ HASH_AlgMD5, HSH_MD5, NULL },
{ HASH_AlgSHA1, HSH_SHA1, NULL },
{ HASH_AlgSHA256, HSH_SHA256, NULL },
{ HASH_AlgSHA384, HSH_SHA384, NULL },
{ HASH_AlgSHA512, HSH_SHA512, NULL },
{ 0, 0, NULL }
{ 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(HSH_Algorithm algorithm)
HSH_GetHashId(const char *name)
{
int i;
if (algorithm == HSH_MD5_NONCRYPTO)
algorithm = HSH_MD5;
for (i = 0; hashes[i].algorithm != 0; i++) {
if (hashes[i].algorithm == algorithm)
for (i = 0; hashes[i].name; i++) {
if (!strcmp(name, hashes[i].name))
break;
}
if (hashes[i].algorithm == 0)
if (!hashes[i].name)
return -1; /* not found */
if (!ictx && !(ictx = NSSLOW_Init()))
@@ -77,38 +72,18 @@ HSH_GetHashId(HSH_Algorithm algorithm)
return i;
}
int
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len)
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 char buf[MAX_HASH_LENGTH];
unsigned int ret = 0;
if (in1_len < 0 || in2_len < 0 || out_len < 0)
return 0;
unsigned int ret;
NSSLOWHASH_Begin(hashes[id].context);
NSSLOWHASH_Update(hashes[id].context, in1, in1_len);
if (in2)
NSSLOWHASH_Update(hashes[id].context, in2, in2_len);
NSSLOWHASH_End(hashes[id].context, buf, &ret, sizeof (buf));
ret = MIN(ret, out_len);
memcpy(out, buf, ret);
NSSLOWHASH_End(hashes[id].context, out, &ret, out_len);
return ret;
}
void
HSH_Finalise(void)
{
int i;
for (i = 0; hashes[i].algorithm != 0; i++) {
if (hashes[i].context)
NSSLOWHASH_Destroy(hashes[i].context);
}
if (ictx)
NSSLOW_Shutdown(ictx);
}

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012, 2018
* 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
@@ -29,57 +29,59 @@
#include "config.h"
#include "hash.h"
#include "util.h"
struct hash {
HSH_Algorithm algorithm;
const char *name;
const char *int_name;
const struct ltc_hash_descriptor *desc;
};
static const struct hash hashes[] = {
{ HSH_MD5, "md5", &md5_desc },
{ "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
{ HSH_SHA1, "sha1", &sha1_desc },
{ "SHA1", "sha1", &sha1_desc },
#endif
#ifdef LTC_SHA256
{ HSH_SHA256, "sha256", &sha256_desc },
{ "SHA256", "sha256", &sha256_desc },
#endif
#ifdef LTC_SHA384
{ HSH_SHA384, "sha384", &sha384_desc },
{ "SHA384", "sha384", &sha384_desc },
#endif
#ifdef LTC_SHA512
{ HSH_SHA512, "sha512", &sha512_desc },
#endif
#ifdef LTC_SHA3
{ HSH_SHA3_224, "sha3-224", &sha3_224_desc },
{ HSH_SHA3_256, "sha3-256", &sha3_256_desc },
{ HSH_SHA3_384, "sha3-384", &sha3_384_desc },
{ HSH_SHA3_512, "sha3-512", &sha3_512_desc },
{ "SHA512", "sha512", &sha512_desc },
#endif
#ifdef LTC_TIGER
{ HSH_TIGER, "tiger", &tiger_desc },
{ "TIGER", "tiger", &tiger_desc },
#endif
#ifdef LTC_WHIRLPOOL
{ HSH_WHIRLPOOL, "whirlpool", &whirlpool_desc },
{ "WHIRLPOOL", "whirlpool", &whirlpool_desc },
#endif
{ 0, NULL, NULL }
{ NULL, NULL, NULL }
};
int
HSH_GetHashId(HSH_Algorithm algorithm)
HSH_GetHashId(const char *name)
{
int i, h;
if (algorithm == HSH_MD5_NONCRYPTO)
algorithm = HSH_MD5;
for (i = 0; hashes[i].algorithm != 0; i++) {
if (hashes[i].algorithm == algorithm)
for (i = 0; hashes[i].name; i++) {
if (!strcmp(name, hashes[i].name))
break;
}
if (hashes[i].algorithm == 0)
if (!hashes[i].name)
return -1; /* not found */
h = find_hash(hashes[i].int_name);
@@ -92,35 +94,23 @@ HSH_GetHashId(HSH_Algorithm algorithm)
return find_hash(hashes[i].int_name);
}
int
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len)
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 char buf[MAX_HASH_LENGTH];
unsigned long len;
int r;
if (in1_len < 0 || in2_len < 0 || out_len < 0)
return 0;
len = sizeof (buf);
len = out_len;
if (in2)
r = hash_memory_multi(id, buf, &len,
in1, (unsigned long)in1_len,
in2, (unsigned long)in2_len, NULL, 0);
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, buf, &len);
r = hash_memory(id, in1, in1_len, out, &len);
if (r != CRYPT_OK)
return 0;
len = MIN(len, out_len);
memcpy(out, buf, len);
return len;
}
void
HSH_Finalise(void)
{
}

344
hwclock.c
View File

@@ -1,344 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2016-2018, 2022
*
* 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 "quantiles.h"
#include "regress.h"
#include "util.h"
/* Minimum and maximum number of samples per clock */
#define MIN_SAMPLES 2
#define MAX_SAMPLES 64
/* Maximum acceptable frequency offset of the clock */
#define MAX_FREQ_OFFSET (2.0 / 3.0)
/* Quantiles for filtering readings by delay */
#define DELAY_QUANT_MIN_K 1
#define DELAY_QUANT_MAX_K 2
#define DELAY_QUANT_Q 10
#define DELAY_QUANT_REPEAT 7
#define DELAY_QUANT_LARGE_STEP_DELAY 1000
#define DELAY_QUANT_MIN_STEP 1.0e-9
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;
double *y_data;
/* Minimum, maximum and current number of samples */
int min_samples;
int max_samples;
int n_samples;
/* Maximum error of the last sample */
double last_err;
/* Minimum interval between samples */
double min_separation;
/* Expected precision of readings */
double precision;
/* 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;
/* Estimated quantiles of reading delay */
QNT_Instance delay_quants;
};
/* ================================================== */
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(int min_samples, int max_samples, double min_separation, double precision)
{
HCL_Instance clock;
min_samples = CLAMP(MIN_SAMPLES, min_samples, MAX_SAMPLES);
max_samples = CLAMP(MIN_SAMPLES, max_samples, MAX_SAMPLES);
max_samples = MAX(min_samples, max_samples);
clock = MallocNew(struct HCL_Instance_Record);
clock->x_data = MallocArray(double, max_samples);
clock->y_data = MallocArray(double, max_samples);
clock->x_data[max_samples - 1] = 0.0;
clock->y_data[max_samples - 1] = 0.0;
clock->min_samples = min_samples;
clock->max_samples = max_samples;
clock->n_samples = 0;
clock->valid_coefs = 0;
clock->min_separation = min_separation;
clock->precision = precision;
clock->delay_quants = QNT_CreateInstance(DELAY_QUANT_MIN_K, DELAY_QUANT_MAX_K,
DELAY_QUANT_Q, DELAY_QUANT_REPEAT,
DELAY_QUANT_LARGE_STEP_DELAY,
DELAY_QUANT_MIN_STEP);
LCL_AddParameterChangeHandler(handle_slew, clock);
return clock;
}
/* ================================================== */
void HCL_DestroyInstance(HCL_Instance clock)
{
LCL_RemoveParameterChangeHandler(handle_slew, clock);
QNT_DestroyInstance(clock->delay_quants);
Free(clock->y_data);
Free(clock->x_data);
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;
}
/* ================================================== */
int
HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3],
struct timespec *hw_ts, struct timespec *local_ts, double *err,
int *quality)
{
double delay, raw_delay, min_delay, low_delay, high_delay, e, pred_err;
double delay_sum, hw_sum, local_sum, local_prec, freq;
int i, min_reading, combined;
struct timespec ts1, ts2;
if (n_readings < 1)
return 0;
/* Work out the current correction multiplier needed to get cooked delays */
LCL_CookTime(&tss[0][0], &ts1, NULL);
LCL_CookTime(&tss[n_readings - 1][2], &ts2, NULL);
if (UTI_CompareTimespecs(&tss[0][0], &tss[n_readings - 1][2]) < 0)
freq = UTI_DiffTimespecsToDouble(&ts1, &ts2) /
UTI_DiffTimespecsToDouble(&tss[0][0], &tss[n_readings - 1][2]);
else
freq = 1.0;
for (i = 0; i < n_readings; i++) {
delay = freq * UTI_DiffTimespecsToDouble(&tss[i][2], &tss[i][0]);
if (delay < 0.0) {
/* Step in the middle of a reading? */
DEBUG_LOG("Bad reading delay=%e", delay);
return 0;
}
if (i == 0 || min_delay > delay) {
min_delay = delay;
min_reading = i;
}
QNT_Accumulate(clock->delay_quants, delay);
}
local_prec = LCL_GetSysPrecisionAsQuantum();
low_delay = QNT_GetQuantile(clock->delay_quants, QNT_GetMinK(clock->delay_quants)) -
QNT_GetMinStep(clock->delay_quants) / 2.0;
high_delay = QNT_GetQuantile(clock->delay_quants, QNT_GetMaxK(clock->delay_quants)) +
QNT_GetMinStep(clock->delay_quants) / 2.0;
low_delay = MIN(low_delay, high_delay);
high_delay = MAX(high_delay, low_delay + local_prec);
/* Combine readings with delay in the expected interval */
for (i = combined = 0, delay_sum = hw_sum = local_sum = 0.0; i < n_readings; i++) {
raw_delay = UTI_DiffTimespecsToDouble(&tss[i][2], &tss[i][0]);
delay = freq * raw_delay;
if (delay < low_delay || delay > high_delay)
continue;
delay_sum += delay;
hw_sum += UTI_DiffTimespecsToDouble(&tss[i][1], &tss[0][1]);
local_sum += UTI_DiffTimespecsToDouble(&tss[i][0], &tss[0][0]) + raw_delay / 2.0;
combined++;
}
DEBUG_LOG("Combined %d readings lo=%e hi=%e", combined, low_delay, high_delay);
if (combined > 0) {
UTI_AddDoubleToTimespec(&tss[0][1], hw_sum / combined, hw_ts);
UTI_AddDoubleToTimespec(&tss[0][0], local_sum / combined, local_ts);
*err = MAX(delay_sum / combined / 2.0, clock->precision);
*quality = 2;
return 1;
}
/* Indicate acceptable quality of the reading with minimum delay if its
interval does not contain the current offset predicted from previous
samples, or a new sample is needed to get the tracking working */
*hw_ts = tss[min_reading][1];
UTI_AddDoubleToTimespec(&tss[min_reading][0], min_delay / freq / 2.0, local_ts);
*err = MAX(min_delay / 2.0, clock->precision);
pred_err = 0.0;
LCL_CookTime(local_ts, &ts1, NULL);
if (!HCL_CookTime(clock, hw_ts, &ts2, &e) ||
((pred_err = UTI_DiffTimespecsToDouble(&ts1, &ts2)) > *err)) {
*quality = 1;
} else {
*quality = 0;
}
DEBUG_LOG("Min-delay reading err=%e prerr=%e ql=%d", *err, pred_err, *quality);
return 1;
}
/* ================================================== */
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 >= clock->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 = clock->max_samples - clock->n_samples; i < clock->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 + clock->max_samples - clock->n_samples,
clock->y_data + clock->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 */
if (clock->n_samples > clock->min_samples)
clock->n_samples -= MIN(best_start, clock->n_samples - clock->min_samples);
/* 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;
}

View File

@@ -1,58 +0,0 @@
/*
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(int min_samples, int max_samples,
double min_separation, double precision);
/* 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);
/* Process new readings of the HW clock in the form of (sys, hw, sys) triplets
and produce a sample which can be accumulated by HCL_AccumulateSample().
Indicate the quality of the sample relative to already processed samples as
a value of 0, 1, or 2, where a sample of quality 0 should normally be
dropped. */
extern int HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3],
struct timespec *hw_ts, struct timespec *local_ts, double *err,
int *quality);
/* 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

388
keys.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2012-2016, 2019-2020
* 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
@@ -30,9 +30,7 @@
#include "sysincl.h"
#include "array.h"
#include "keys.h"
#include "cmac.h"
#include "cmdparse.h"
#include "conf.h"
#include "memory.h"
@@ -40,58 +38,82 @@
#include "local.h"
#include "logging.h"
/* Consider 80 bits as the absolute minimum for a secure key */
#define MIN_SECURE_KEY_LENGTH 10
typedef enum {
NTP_MAC,
CMAC,
} KeyClass;
typedef struct {
uint32_t id;
int type;
int length;
KeyClass class;
union {
struct {
unsigned char *value;
int hash_id;
} ntp_mac;
CMC_Instance cmac;
} data;
unsigned long id;
char *val;
int len;
int hash_id;
int auth_delay;
} Key;
static ARR_Instance keys;
#define MAX_KEYS 256
static int n_keys;
static Key keys[MAX_KEYS];
static int command_key_valid;
static int command_key_id;
static int cache_valid;
static uint32_t cache_key_id;
static unsigned long cache_key_id;
static int cache_key_pos;
/* ================================================== */
static void
free_keys(void)
static int
generate_key(unsigned long key_id)
{
unsigned int i;
Key *key;
#ifdef GENERATE_SHA1_KEY
unsigned char key[20];
const char *hashname = "SHA1";
#else
unsigned char key[16];
const char *hashname = "MD5";
#endif
const char *key_file, *rand_dev = "/dev/urandom";
FILE *f;
struct stat st;
int i;
for (i = 0; i < ARR_GetSize(keys); i++) {
key = ARR_GetElement(keys, i);
switch (key->class) {
case NTP_MAC:
Free(key->data.ntp_mac.value);
break;
case CMAC:
CMC_DestroyInstance(key->data.cmac);
break;
default:
assert(0);
}
key_file = CNF_GetKeysFile();
if (!key_file)
return 0;
f = fopen(rand_dev, "r");
if (!f || fread(key, sizeof (key), 1, f) != 1) {
if (f)
fclose(f);
LOG_FATAL(LOGF_Keys, "Could not read %s", rand_dev);
return 0;
}
fclose(f);
f = fopen(key_file, "a");
if (!f) {
LOG_FATAL(LOGF_Keys, "Could not open keyfile %s for writing", key_file);
return 0;
}
ARR_SetSize(keys, 0);
cache_valid = 0;
/* Make sure the keyfile is not world-readable */
if (stat(key_file, &st) || chmod(key_file, st.st_mode & 0770)) {
fclose(f);
LOG_FATAL(LOGF_Keys, "Could not change permissions of keyfile %s", key_file);
return 0;
}
fprintf(f, "\n%lu %s HEX:", key_id, hashname);
for (i = 0; i < sizeof (key); i++)
fprintf(f, "%02hhX", key[i]);
fprintf(f, "\n");
fclose(f);
/* Erase the key from stack */
memset(key, 0, sizeof (key));
LOG(LOGS_INFO, LOGF_Keys, "Generated key %lu", key_id);
return 1;
}
/* ================================================== */
@@ -99,9 +121,15 @@ free_keys(void)
void
KEY_Initialise(void)
{
keys = ARR_CreateInstance(sizeof (Key));
n_keys = 0;
command_key_valid = 0;
cache_valid = 0;
KEY_Reload();
if (CNF_GetGenerateCommandKey() && !KEY_KeyKnown(KEY_GetCommandKey())) {
if (generate_key(KEY_GetCommandKey()))
KEY_Reload();
}
}
/* ================================================== */
@@ -109,35 +137,37 @@ KEY_Initialise(void)
void
KEY_Finalise(void)
{
free_keys();
ARR_DestroyInstance(keys);
}
/* ================================================== */
static Key *
get_key(unsigned int index)
{
return ((Key *)ARR_GetElements(keys)) + index;
}
/* ================================================== */
/* Decode key encoded in ASCII or HEX */
static int
decode_key(char *key)
determine_hash_delay(unsigned long key_id)
{
int len = strlen(key);
NTP_Packet pkt;
struct timeval before, after;
unsigned long usecs, min_usecs=0;
int i;
if (!strncmp(key, "ASCII:", 6)) {
memmove(key, key + 6, len - 6);
return len - 6;
} else if (!strncmp(key, "HEX:", 4)) {
return UTI_HexToBytes(key + 4, key, len);
} else {
/* assume ASCII */
return len;
for (i = 0; i < 10; i++) {
LCL_ReadRawTime(&before);
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_SIZE,
(unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
LCL_ReadRawTime(&after);
usecs = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec);
if (i == 0 || usecs < min_usecs) {
min_usecs = usecs;
}
}
/* Add on a bit extra to allow for copying, conversions etc */
min_usecs += min_usecs >> 4;
DEBUG_LOG(LOGF_Keys, "authentication delay for key %lu: %ld useconds", key_id, min_usecs);
return min_usecs;
}
/* ================================================== */
@@ -165,16 +195,18 @@ compare_keys_by_id(const void *a, const void *b)
void
KEY_Reload(void)
{
unsigned int i, line_number, key_length, cmac_key_length;
int i, line_number;
FILE *in;
char line[2048], *key_file, *key_value;
const char *key_type;
HSH_Algorithm hash_algorithm;
CMC_Algorithm cmac_algorithm;
int hash_id;
Key key;
unsigned long key_id;
char line[2048], *keyval, *key_file;
const char *hashname;
free_keys();
for (i=0; i<n_keys; i++) {
Free(keys[i].val);
}
n_keys = 0;
command_key_valid = 0;
cache_valid = 0;
key_file = CNF_GetKeysFile();
line_number = 0;
@@ -182,12 +214,9 @@ KEY_Reload(void)
if (!key_file)
return;
if (!UTI_CheckFilePermissions(key_file, 0771))
;
in = UTI_OpenFile(NULL, key_file, NULL, 'r', 0);
in = fopen(key_file, "r");
if (!in) {
LOG(LOGS_WARN, "Could not open keyfile %s", key_file);
LOG(LOGS_WARN, LOGF_Keys, "Could not open keyfile %s", key_file);
return;
}
@@ -198,57 +227,27 @@ KEY_Reload(void)
if (!*line)
continue;
memset(&key, 0, sizeof (key));
if (!CPS_ParseKey(line, &key.id, &key_type, &key_value)) {
LOG(LOGS_WARN, "Could not parse key at line %u in file %s", line_number, key_file);
if (!CPS_ParseKey(line, &key_id, &hashname, &keyval)) {
LOG(LOGS_WARN, LOGF_Keys, "Could not parse key at line %d in file %s", line_number, key_file);
continue;
}
key_length = decode_key(key_value);
if (key_length == 0) {
LOG(LOGS_WARN, "Could not decode key %"PRIu32, key.id);
keys[n_keys].hash_id = HSH_GetHashId(hashname);
if (keys[n_keys].hash_id < 0) {
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %lu", key_id);
continue;
}
hash_algorithm = UTI_HashNameToAlgorithm(key_type);
cmac_algorithm = UTI_CmacNameToAlgorithm(key_type);
if (hash_algorithm != 0) {
hash_id = HSH_GetHashId(hash_algorithm);
if (hash_id < 0) {
LOG(LOGS_WARN, "Unsupported %s in key %"PRIu32, "hash function", key.id);
continue;
}
key.class = NTP_MAC;
key.type = hash_algorithm;
key.length = key_length;
key.data.ntp_mac.value = MallocArray(unsigned char, key_length);
memcpy(key.data.ntp_mac.value, key_value, key_length);
key.data.ntp_mac.hash_id = hash_id;
} else if (cmac_algorithm != 0) {
cmac_key_length = CMC_GetKeyLength(cmac_algorithm);
if (cmac_key_length == 0) {
LOG(LOGS_WARN, "Unsupported %s in key %"PRIu32, "cipher", key.id);
continue;
} else if (cmac_key_length != key_length) {
LOG(LOGS_WARN, "Invalid length of %s key %"PRIu32" (expected %u bits)",
key_type, key.id, 8 * cmac_key_length);
continue;
}
key.class = CMAC;
key.type = cmac_algorithm;
key.length = key_length;
key.data.cmac = CMC_CreateInstance(cmac_algorithm, (unsigned char *)key_value,
key_length);
assert(key.data.cmac);
} else {
LOG(LOGS_WARN, "Invalid type in key %"PRIu32, key.id);
keys[n_keys].len = UTI_DecodePasswordFromText(keyval);
if (!keys[n_keys].len) {
LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %lu", key_id);
continue;
}
ARR_AppendElement(keys, &key);
keys[n_keys].id = key_id;
keys[n_keys].val = MallocArray(char, keys[n_keys].len);
memcpy(keys[n_keys].val, keyval, keys[n_keys].len);
n_keys++;
}
fclose(in);
@@ -256,46 +255,50 @@ KEY_Reload(void)
/* Sort keys into order. Note, if there's a duplicate, it is
arbitrary which one we use later - the user should have been
more careful! */
qsort(ARR_GetElements(keys), ARR_GetSize(keys), sizeof (Key), compare_keys_by_id);
LOG(LOGS_INFO, "Loaded %u symmetric keys", ARR_GetSize(keys));
qsort((void *) keys, n_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);
for (i = 1; i < n_keys; i++) {
if (keys[i - 1].id == keys[i].id) {
LOG(LOGS_WARN, LOGF_Keys, "Detected duplicate key %lu", keys[i].id);
}
}
/* Erase any passwords from stack */
memset(line, 0, sizeof (line));
for (i=0; i<n_keys; i++) {
keys[i].auth_delay = determine_hash_delay(keys[i].id);
}
}
/* ================================================== */
static int
lookup_key(uint32_t id)
lookup_key(unsigned long id)
{
Key specimen, *where, *keys_ptr;
Key specimen, *where;
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);
where = (Key *) bsearch((void *)&specimen, (void *)keys, n_keys, sizeof(Key), compare_keys_by_id);
if (!where) {
return -1;
} else {
pos = where - keys_ptr;
pos = where - keys;
return pos;
}
}
/* ================================================== */
static Key *
get_key_by_id(uint32_t key_id)
static int
get_key_pos(unsigned long key_id)
{
int position;
if (cache_valid && key_id == cache_key_id)
return get_key(cache_key_pos);
return cache_key_pos;
position = lookup_key(key_id);
@@ -303,136 +306,81 @@ get_key_by_id(uint32_t key_id)
cache_valid = 1;
cache_key_pos = position;
cache_key_id = key_id;
return get_key(position);
}
return NULL;
return position;
}
/* ================================================== */
int
KEY_KeyKnown(uint32_t key_id)
unsigned long
KEY_GetCommandKey(void)
{
return get_key_by_id(key_id) != NULL;
}
/* ================================================== */
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;
switch (key->class) {
case NTP_MAC:
return HSH_Hash(key->data.ntp_mac.hash_id, buf, 0, buf, 0, buf, sizeof (buf));
case CMAC:
return CMC_Hash(key->data.cmac, buf, 0, buf, sizeof (buf));
default:
assert(0);
return 0;
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
}
return command_key_id;
}
/* ================================================== */
int
KEY_CheckKeyLength(uint32_t key_id)
KEY_KeyKnown(unsigned long key_id)
{
Key *key;
key = get_key_by_id(key_id);
if (!key)
return 0;
return key->length >= MIN_SECURE_KEY_LENGTH;
return get_key_pos(key_id) >= 0;
}
/* ================================================== */
int
KEY_GetKeyInfo(uint32_t key_id, int *type, int *bits)
KEY_GetAuthDelay(unsigned long key_id)
{
Key *key;
int key_pos;
key = get_key_by_id(key_id);
key_pos = get_key_pos(key_id);
if (!key)
if (key_pos < 0) {
return 0;
*type = key->type;
*bits = 8 * key->length;
return 1;
}
/* ================================================== */
static int
generate_auth(Key *key, const void *data, int data_len, unsigned char *auth, int auth_len)
{
switch (key->class) {
case NTP_MAC:
return HSH_Hash(key->data.ntp_mac.hash_id, key->data.ntp_mac.value,
key->length, data, data_len, auth, auth_len);
case CMAC:
return CMC_Hash(key->data.cmac, data, data_len, auth, auth_len);
default:
return 0;
}
}
/* ================================================== */
static int
check_auth(Key *key, const void *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_auth(key, data, data_len, buf, sizeof (buf));
return MIN(hash_len, trunc_len) == auth_len && UTI_IsMemoryEqual(buf, auth, auth_len);
return keys[key_pos].auth_delay;
}
/* ================================================== */
int
KEY_GenerateAuth(uint32_t key_id, const void *data, int data_len,
unsigned char *auth, int auth_len)
KEY_GenerateAuth(unsigned long key_id, const unsigned char *data, int data_len,
unsigned char *auth, int auth_len)
{
Key *key;
int key_pos;
key = get_key_by_id(key_id);
key_pos = get_key_pos(key_id);
if (!key)
if (key_pos < 0) {
return 0;
}
return generate_auth(key, data, data_len, auth, auth_len);
return UTI_GenerateNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}
/* ================================================== */
int
KEY_CheckAuth(uint32_t key_id, const void *data, int data_len,
const unsigned char *auth, int auth_len, int trunc_len)
KEY_CheckAuth(unsigned long key_id, const unsigned char *data, int data_len,
const unsigned char *auth, int auth_len)
{
Key *key;
int key_pos;
key = get_key_by_id(key_id);
key_pos = get_key_pos(key_id);
if (!key)
if (key_pos < 0) {
return 0;
}
return check_auth(key, data, data_len, auth, auth_len, trunc_len);
return UTI_CheckNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}

19
keys.h
View File

@@ -27,21 +27,20 @@
#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_KeyKnown(uint32_t key_id);
extern int KEY_GetAuthLength(uint32_t key_id);
extern int KEY_CheckKeyLength(uint32_t key_id);
extern int KEY_GetKeyInfo(uint32_t key_id, int *type, int *bits);
extern unsigned long KEY_GetCommandKey(void);
extern int KEY_GenerateAuth(uint32_t key_id, const void *data, int data_len,
unsigned char *auth, int auth_len);
extern int KEY_CheckAuth(uint32_t key_id, const void *data, int data_len,
const unsigned char *auth, int auth_len, int trunc_len);
extern int KEY_GetKey(unsigned long key_id, char **key, int *len);
extern int KEY_KeyKnown(unsigned long key_id);
extern int KEY_GetAuthDelay(unsigned long key_id);
extern int KEY_GenerateAuth(unsigned long key_id, const unsigned char *data,
int data_len, unsigned char *auth, int auth_len);
extern int KEY_CheckAuth(unsigned long key_id, const unsigned char *data,
int data_len, const unsigned char *auth, int auth_len);
#endif /* GOT_KEYS_H */

272
leapdb.c
View File

@@ -1,272 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2009-2018, 2020, 2022
* Copyright (C) Patrick Oppenlander 2023, 2024
*
* 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 leap second information. */
#include "config.h"
#include "sysincl.h"
#include "conf.h"
#include "leapdb.h"
#include "logging.h"
#include "util.h"
/* ================================================== */
/* Source of leap second data */
enum {
SRC_NONE,
SRC_TIMEZONE,
SRC_LIST,
} leap_src;
/* Offset between leap-seconds.list timestamp epoch and Unix epoch.
leap-seconds.list epoch is 1 Jan 1900, 00:00:00 */
#define LEAP_SEC_LIST_OFFSET 2208988800
/* ================================================== */
static NTP_Leap
get_tz_leap(time_t when, int *tai_offset)
{
struct tm stm, *tm;
time_t t;
char *tz_env, tz_orig[128];
NTP_Leap tz_leap = LEAP_Normal;
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", CNF_GetLeapSecTimezone(), 1);
tzset();
/* Get the TAI-UTC offset, which started at the epoch at 10 seconds */
t = mktime(&stm);
if (t != -1)
*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;
return tz_leap;
}
/* ================================================== */
static NTP_Leap
get_list_leap(time_t when, int *tai_offset)
{
FILE *f;
char line[1024];
NTP_Leap ret_leap = LEAP_Normal;
int ret_tai_offset = 0, prev_lsl_tai_offset = 10;
int64_t when1900, lsl_updated = 0, lsl_expiry = 0;
const char *leap_sec_list = CNF_GetLeapSecList();
if (!(f = UTI_OpenFile(NULL, leap_sec_list, NULL, 'r', 0))) {
LOG(LOGS_ERR, "Failed to open leap seconds list %s", leap_sec_list);
goto out;
}
/* Leap second happens at midnight */
when = (when / (24 * 3600) + 1) * (24 * 3600);
/* leap-seconds.list timestamps are relative to 1 Jan 1900, 00:00:00 */
when1900 = (int64_t)when + LEAP_SEC_LIST_OFFSET;
while (fgets(line, sizeof line, f)) {
int64_t lsl_when;
int lsl_tai_offset;
char *p;
/* Ignore blank lines */
for (p = line; *p && isspace((unsigned char)*p); ++p)
;
if (!*p)
continue;
if (*line == '#') {
/* Update time line starts with #$ */
if (line[1] == '$' && sscanf(line + 2, "%"SCNd64, &lsl_updated) != 1)
goto error;
/* Expiration time line starts with #@ */
if (line[1] == '@' && sscanf(line + 2, "%"SCNd64, &lsl_expiry) != 1)
goto error;
/* Comment or a special comment we don't care about */
continue;
}
/* Leap entry */
if (sscanf(line, "%"SCNd64" %d", &lsl_when, &lsl_tai_offset) != 2)
goto error;
if (when1900 == lsl_when) {
if (lsl_tai_offset > prev_lsl_tai_offset)
ret_leap = LEAP_InsertSecond;
else if (lsl_tai_offset < prev_lsl_tai_offset)
ret_leap = LEAP_DeleteSecond;
/* When is rounded to the end of the day, so offset hasn't changed yet! */
ret_tai_offset = prev_lsl_tai_offset;
} else if (when1900 > lsl_when) {
ret_tai_offset = lsl_tai_offset;
}
prev_lsl_tai_offset = lsl_tai_offset;
}
/* Make sure the file looks sensible */
if (!feof(f) || !lsl_updated || !lsl_expiry)
goto error;
if (when1900 >= lsl_expiry)
LOG(LOGS_WARN, "Leap second list %s needs update", leap_sec_list);
goto out;
error:
if (f)
fclose(f);
LOG(LOGS_ERR, "Failed to parse leap seconds list %s", leap_sec_list);
return LEAP_Normal;
out:
if (f)
fclose(f);
*tai_offset = ret_tai_offset;
return ret_leap;
}
/* ================================================== */
static int
check_leap_source(NTP_Leap (*src)(time_t when, int *tai_offset))
{
int tai_offset = 0;
/* Check that the leap second source has good data for Jun 30 2012 and Dec 31 2012 */
if (src(1341014400, &tai_offset) == LEAP_InsertSecond && tai_offset == 34 &&
src(1356912000, &tai_offset) == LEAP_Normal && tai_offset == 35)
return 1;
return 0;
}
/* ================================================== */
void
LDB_Initialise(void)
{
const char *leap_tzname, *leap_sec_list;
leap_tzname = CNF_GetLeapSecTimezone();
if (leap_tzname && !check_leap_source(get_tz_leap)) {
LOG(LOGS_WARN, "Timezone %s failed leap second check, ignoring", leap_tzname);
leap_tzname = NULL;
}
leap_sec_list = CNF_GetLeapSecList();
if (leap_sec_list && !check_leap_source(get_list_leap)) {
LOG(LOGS_WARN, "Leap second list %s failed check, ignoring", leap_sec_list);
leap_sec_list = NULL;
}
if (leap_sec_list) {
LOG(LOGS_INFO, "Using leap second list %s", leap_sec_list);
leap_src = SRC_LIST;
} else if (leap_tzname) {
LOG(LOGS_INFO, "Using %s timezone to obtain leap second data", leap_tzname);
leap_src = SRC_TIMEZONE;
}
}
/* ================================================== */
NTP_Leap
LDB_GetLeap(time_t when, int *tai_offset)
{
static time_t last_ldb_leap_check;
static NTP_Leap ldb_leap;
static int ldb_tai_offset;
/* Do this check at most twice a day */
when = when / (12 * 3600) * (12 * 3600);
if (last_ldb_leap_check == when)
goto out;
last_ldb_leap_check = when;
ldb_leap = LEAP_Normal;
ldb_tai_offset = 0;
switch (leap_src) {
case SRC_NONE:
break;
case SRC_TIMEZONE:
ldb_leap = get_tz_leap(when, &ldb_tai_offset);
break;
case SRC_LIST:
ldb_leap = get_list_leap(when, &ldb_tai_offset);
break;
}
out:
*tai_offset = ldb_tai_offset;
return ldb_leap;
}
/* ================================================== */
void
LDB_Finalise(void)
{
/* Nothing to do */
}

440
local.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011, 2014-2015
* 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
@@ -36,7 +36,6 @@
#include "local.h"
#include "localp.h"
#include "memory.h"
#include "smooth.h"
#include "util.h"
#include "logging.h"
@@ -45,9 +44,6 @@
/* 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;
@@ -60,7 +56,6 @@ 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;
/* ================================================== */
@@ -97,142 +92,8 @@ static double precision_quantum;
static double max_clock_error;
#define NSEC_PER_SEC 1000000000
/* ================================================== */
/* Ask the system for the resolution of the system clock. The Linux
clock_getres() is not usable, because it reports the internal timer
resolution, which is 1 ns when high-resolution timers are enabled,
even when using a lower-resolution clocksource. */
static int
get_clock_resolution(void)
{
#if defined(HAVE_CLOCK_GETTIME) && !defined(LINUX)
struct timespec res;
if (clock_getres(CLOCK_REALTIME, &res) < 0)
return 0;
return NSEC_PER_SEC * res.tv_sec + res.tv_nsec;
#else
return 0;
#endif
}
/* ================================================== */
#if defined(LINUX) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC_RAW)
static int
compare_ints(const void *a, const void *b)
{
return *(const int *)a - *(const int *)b;
}
#define READINGS 64
/* On Linux, try to measure the actual resolution of the system
clock by performing a varying amount of busy work between clock
readings and finding the minimum change in the measured interval.
Require a change of at least two nanoseconds to ignore errors
caused by conversion to timespec. Use the raw monotonic clock
to avoid the impact of potential frequency changes due to NTP
adjustments made by other processes, and the kernel dithering of
the 32-bit multiplier. */
static int
measure_clock_resolution(void)
{
int i, j, b, busy, diffs[READINGS - 1], diff2, min;
struct timespec start_ts, ts[READINGS];
uint32_t acc;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_ts) < 0)
return 0;
for (acc = 0, busy = 1; busy < 100000; busy = busy * 3 / 2 + 1) {
for (i = 0, b = busy * READINGS; i < READINGS; i++, b -= busy) {
if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts[i]) < 0)
return 0;
for (j = b; j > 0; j--)
acc += (acc & 1) + (uint32_t)ts[i].tv_nsec;
}
/* Give up after 0.1 seconds */
if (UTI_DiffTimespecsToDouble(&ts[READINGS - 1], &start_ts) > 0.1) {
DEBUG_LOG("Measurement too slow");
return 0;
}
for (i = 0; i < READINGS - 1; i++) {
diffs[i] = NSEC_PER_SEC * (ts[i + 1].tv_sec - ts[i].tv_sec) +
(ts[i + 1].tv_nsec - ts[i].tv_nsec);
/* Make sure the differences are sane. A resolution larger than the
reading time will be measured in measure_clock_read_delay(). */
if (diffs[i] <= 0 || diffs[i] > NSEC_PER_SEC)
return 0;
}
/* Sort the differences and keep values unique within 1 ns from the
first half of the array, which are less likely to be impacted by CPU
interruptions */
qsort(diffs, READINGS - 1, sizeof (diffs[0]), compare_ints);
for (i = 1, j = 0; i < READINGS / 2; i++) {
if (diffs[j] + 1 < diffs[i])
diffs[++j] = diffs[i];
}
j++;
#if 0
for (i = 0; i < j; i++)
DEBUG_LOG("busy %d diff %d %d", busy, i, diffs[i]);
#endif
/* Require at least three unique differences to be more confident
with the result */
if (j < 3)
continue;
/* Find the smallest difference between the unique differences */
for (i = 1, min = 0; i < j; i++) {
diff2 = diffs[i] - diffs[i - 1];
if (min == 0 || min > diff2)
min = diff2;
}
if (min == 0)
continue;
/* Prevent the compiler from optimising the busy work out */
if (acc == 0)
min += 1;
return min;
}
return 0;
}
#else
static int
measure_clock_resolution(void)
{
return 0;
}
#endif
/* ================================================== */
/* As a fallback, measure how long it takes to read the clock. It
typically takes longer than the resolution of the clock (and it
depends on the CPU speed), i.e. every reading gives a different
value, but handle also low-resolution clocks that might give
the same reading multiple times. */
/* 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
@@ -240,55 +101,40 @@ measure_clock_resolution(void)
under 1s of busy waiting. */
#define NITERS 100
static int
measure_clock_read_delay(void)
static void
calculate_sys_precision(void)
{
struct timespec ts, old_ts;
int iters, diff, best;
struct timeval tv, old_tv;
int dusec, best_dusec;
int iters;
LCL_ReadRawTime(&old_ts);
/* Assume we must be better than a second */
best = NSEC_PER_SEC;
gettimeofday(&old_tv, NULL);
best_dusec = 1000000; /* Assume we must be better than a second */
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;
gettimeofday(&tv, NULL);
dusec = 1000000*(tv.tv_sec - old_tv.tv_sec) + (tv.tv_usec - old_tv.tv_usec);
old_tv = tv;
if (dusec > 0) {
if (dusec < best_dusec) {
best_dusec = dusec;
}
iters++;
}
} while (iters < NITERS);
assert(best > 0);
assert(best_dusec > 0);
return best;
}
precision_quantum = best_dusec * 1.0e-6;
/* ================================================== */
/* Get rounded log2 value of the measured precision */
precision_log = 0;
while (best_dusec < 707107) {
precision_log--;
best_dusec *= 2;
}
static double
measure_clock_precision(void)
{
int res, delay, prec;
res = get_clock_resolution();
if (res <= 0)
res = measure_clock_resolution();
delay = measure_clock_read_delay();
if (res > 0)
prec = MIN(res, delay);
else
prec = delay;
return prec / 1.0e9;
DEBUG_LOG(LOGF_Local, "Clock precision %.9f (%d)", precision_quantum, precision_log);
}
/* ================================================== */
@@ -312,21 +158,7 @@ LCL_Initialise(void)
current_freq_ppm = 0.0;
temp_comp_ppm = 0.0;
precision_quantum = CNF_GetClockPrecision();
if (precision_quantum <= 0.0)
precision_quantum = measure_clock_precision();
precision_quantum = CLAMP(1.0e-9, precision_quantum, 1.0);
precision_log = round(log(precision_quantum) / log(2.0));
/* NTP code doesn't support smaller log than -30 */
assert(precision_log >= -30);
DEBUG_LOG("Clock precision %.9f (%d)", precision_quantum, precision_log);
/* 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);
calculate_sys_precision();
max_clock_error = CNF_GetMaxClockError() * 1e-6;
}
@@ -336,9 +168,6 @@ LCL_Initialise(void)
void
LCL_Finalise(void)
{
/* Make sure all handlers have been removed */
BRIEF_ASSERT(change_list.next == &change_list);
BRIEF_ASSERT(dispersion_notify_list.next == &dispersion_notify_list);
}
/* ================================================== */
@@ -376,7 +205,9 @@ LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything
/* Check that the handler is not already registered */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
BRIEF_ASSERT(ptr->handler != handler || ptr->anything != anything);
if (!(ptr->handler != handler || ptr->anything != anything)) {
assert(0);
}
}
new_entry = MallocNew(ChangeListEntry);
@@ -416,7 +247,7 @@ void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *
ptr->next->prev = ptr->prev;
ptr->prev->next = ptr->next;
Free(ptr);
free(ptr);
}
/* ================================================== */
@@ -430,7 +261,7 @@ LCL_IsFirstParameterChangeHandler(LCL_ParameterChangeHandler handler)
/* ================================================== */
static void
invoke_parameter_change_handlers(struct timespec *raw, struct timespec *cooked,
invoke_parameter_change_handlers(struct timeval *raw, struct timeval *cooked,
double dfreq, double doffset,
LCL_ChangeType change_type)
{
@@ -450,7 +281,9 @@ LCL_AddDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anythi
/* Check that the handler is not already registered */
for (ptr = dispersion_notify_list.next; ptr != &dispersion_notify_list; ptr = ptr->next) {
BRIEF_ASSERT(ptr->handler != handler || ptr->anything != anything);
if (!(ptr->handler != handler || ptr->anything != anything)) {
assert(0);
}
}
new_entry = MallocNew(DispersionNotifyListEntry);
@@ -491,33 +324,27 @@ void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void
ptr->next->prev = ptr->prev;
ptr->prev->next = ptr->next;
Free(ptr);
free(ptr);
}
/* ================================================== */
/* At the moment, this is just gettimeofday(), because
I can't think of a Unix system where it would not be */
void
LCL_ReadRawTime(struct timeval *result)
{
if (gettimeofday(result, NULL) < 0) {
LOG_FATAL(LOGF_Local, "gettimeofday() failed");
}
}
/* ================================================== */
void
LCL_ReadRawTime(struct timespec *ts)
LCL_ReadCookedTime(struct timeval *result, double *err)
{
#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;
struct timeval raw;
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, result, err);
@@ -526,18 +353,18 @@ LCL_ReadCookedTime(struct timespec *result, double *err)
/* ================================================== */
void
LCL_CookTime(struct timespec *raw, struct timespec *cooked, double *err)
LCL_CookTime(struct timeval *raw, struct timeval *cooked, double *err)
{
double correction;
LCL_GetOffsetCorrection(raw, &correction, err);
UTI_AddDoubleToTimespec(raw, correction, cooked);
UTI_AddDoubleToTimeval(raw, correction, cooked);
}
/* ================================================== */
void
LCL_GetOffsetCorrection(struct timespec *raw, double *correction, double *err)
LCL_GetOffsetCorrection(struct timeval *raw, double *correction, double *err)
{
/* Call system specific driver to get correction */
(*drv_offset_convert)(raw, correction, err);
@@ -562,44 +389,15 @@ LCL_ReadAbsoluteFrequency(void)
}
/* ================================================== */
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;
struct timeval raw, cooked;
double dfreq;
afreq_ppm = clamp_freq(afreq_ppm);
/* Apply temperature compensation */
if (temp_comp_ppm != 0.0) {
afreq_ppm = afreq_ppm * (1.0 - 1.0e-6 * temp_comp_ppm) - temp_comp_ppm;
@@ -626,7 +424,7 @@ LCL_SetAbsoluteFrequency(double afreq_ppm)
void
LCL_AccumulateDeltaFrequency(double dfreq)
{
struct timespec raw, cooked;
struct timeval raw, cooked;
double old_freq_ppm;
old_freq_ppm = current_freq_ppm;
@@ -637,8 +435,6 @@ LCL_AccumulateDeltaFrequency(double dfreq)
current_freq_ppm += dfreq * (1.0e6 - current_freq_ppm);
current_freq_ppm = clamp_freq(current_freq_ppm);
/* Call the system-specific driver for setting the frequency */
current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 - old_freq_ppm);
@@ -652,10 +448,10 @@ LCL_AccumulateDeltaFrequency(double dfreq)
/* ================================================== */
int
void
LCL_AccumulateOffset(double offset, double corr_rate)
{
struct timespec raw, cooked;
struct timeval 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 */
@@ -663,23 +459,18 @@ LCL_AccumulateOffset(double offset, double corr_rate)
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&cooked, offset))
return 0;
(*drv_accrue_offset)(offset, corr_rate);
/* Dispatch to all handlers */
invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeAdjust);
return 1;
}
/* ================================================== */
int
void
LCL_ApplyStepOffset(double offset)
{
struct timespec raw, cooked;
struct timeval 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 */
@@ -687,31 +478,18 @@ LCL_ApplyStepOffset(double offset)
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);
(*drv_apply_step_offset)(offset);
/* 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,
LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
double offset, double dispersion)
{
LCL_CancelOffsetCorrection();
/* Dispatch to all handlers */
invoke_parameter_change_handlers(raw, cooked, 0.0, offset, LCL_ChangeUnknownStep);
@@ -721,26 +499,9 @@ LCL_NotifyExternalTimeStep(struct timespec *raw, struct timespec *cooked,
/* ================================================== */
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);
}
/* ================================================== */
int
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
{
struct timespec raw, cooked;
struct timeval raw, cooked;
double old_freq_ppm;
LCL_ReadRawTime(&raw);
@@ -748,9 +509,6 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
to the change we are about to make */
LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&cooked, doffset))
return 0;
old_freq_ppm = current_freq_ppm;
/* Work out new absolute frequency. Note that absolute frequencies
@@ -758,9 +516,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
terms of the gradient of the (offset) v (local time) function. */
current_freq_ppm += dfreq * (1.0e6 - current_freq_ppm);
current_freq_ppm = clamp_freq(current_freq_ppm);
DEBUG_LOG("old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
DEBUG_LOG(LOGF_Local, "old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
old_freq_ppm, current_freq_ppm, doffset);
/* Call the system-specific driver for setting the frequency */
@@ -771,26 +527,6 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
/* Dispatch to all handlers */
invoke_parameter_change_handlers(&raw, &cooked, dfreq, doffset, LCL_ChangeAdjust);
return 1;
}
/* ================================================== */
int
LCL_AccumulateFrequencyAndOffsetNoHandlers(double dfreq, double doffset, double corr_rate)
{
ChangeListEntry *first_handler;
int r;
first_handler = change_list.next;
change_list.next = &change_list;
r = LCL_AccumulateFrequencyAndOffset(dfreq, doffset, corr_rate);
change_list.next = first_handler;
return r;
}
/* ================================================== */
@@ -814,8 +550,7 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert,
lcl_SetLeapDriver set_leap,
lcl_SetSyncStatusDriver set_sync_status)
lcl_SetLeapDriver set_leap)
{
drv_read_freq = read_freq;
drv_set_freq = set_freq;
@@ -823,11 +558,10 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
drv_apply_step_offset = apply_step_offset;
drv_offset_convert = offset_convert;
drv_set_leap = set_leap;
drv_set_sync_status = set_sync_status;
current_freq_ppm = (*drv_read_freq)();
DEBUG_LOG("Local freq=%.3fppm", current_freq_ppm);
DEBUG_LOG(LOGF_Local, "Local freq=%.3fppm", current_freq_ppm);
}
/* ================================================== */
@@ -837,24 +571,17 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
int
LCL_MakeStep(void)
{
struct timespec raw;
struct timeval 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)) {
/* Revert the correction */
LCL_AccumulateOffset(-correction, 0.0);
return 0;
}
LCL_ApplyStepOffset(-correction);
LOG(LOGS_WARN, "System clock was stepped by %.6f seconds", correction);
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.6f seconds", correction);
return 1;
}
@@ -862,31 +589,10 @@ LCL_MakeStep(void)
/* ================================================== */
void
LCL_CancelOffsetCorrection(void)
{
struct timespec raw;
double correction;
LCL_ReadRawTime(&raw);
LCL_GetOffsetCorrection(&raw, &correction, NULL);
LCL_AccumulateOffset(correction, 0.0);
}
/* ================================================== */
int
LCL_CanSystemLeap(void)
{
return drv_set_leap ? 1 : 0;
}
/* ================================================== */
void
LCL_SetSystemLeap(int leap, int tai_offset)
LCL_SetLeap(int leap)
{
if (drv_set_leap) {
(drv_set_leap)(leap, tai_offset);
(drv_set_leap)(leap);
}
}
@@ -919,13 +625,3 @@ LCL_SetTempComp(double comp)
}
/* ================================================== */
void
LCL_SetSyncStatus(int synchronised, double est_error, double max_error)
{
if (drv_set_sync_status) {
(drv_set_sync_status)(synchronised, est_error, max_error);
}
}
/* ================================================== */

50
local.h
View File

@@ -31,8 +31,9 @@
#include "sysincl.h"
/* Read the system clock */
extern void LCL_ReadRawTime(struct timespec *ts);
/* Read the system clock. This is analogous to gettimeofday(),
but with the timezone information ignored */
extern void LCL_ReadRawTime(struct timeval *);
/* Read the system clock, corrected according to all accumulated
drifts and uncompensated offsets.
@@ -43,15 +44,15 @@ extern void LCL_ReadRawTime(struct timespec *ts);
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);
extern void LCL_ReadCookedTime(struct timeval *t, double *err);
/* Convert raw time to cooked. */
extern void LCL_CookTime(struct timespec *raw, struct timespec *cooked, double *err);
extern void LCL_CookTime(struct timeval *raw, struct timeval *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);
extern void LCL_GetOffsetCorrection(struct timeval *raw, double *correction, double *err);
/* Type of routines that may be invoked as callbacks when there is a
change to the frequency or offset.
@@ -78,7 +79,7 @@ typedef enum {
} LCL_ChangeType;
typedef void (*LCL_ParameterChangeHandler)
(struct timespec *raw, struct timespec *cooked,
(struct timeval *raw, struct timeval *cooked,
double dfreq,
double doffset,
LCL_ChangeType change_type,
@@ -149,7 +150,7 @@ extern void LCL_AccumulateDeltaFrequency(double dfreq);
forwards (i.e. it is currently slow of true time). Provided is also
a suggested correction rate (correction time * offset). */
extern int LCL_AccumulateOffset(double offset, double corr_rate);
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
@@ -158,25 +159,16 @@ extern int LCL_AccumulateOffset(double offset, double corr_rate);
the system clock is fast on true time, i.e. it needs to be stepped
backwards. (Same convention as for AccumulateOffset routine). */
extern int LCL_ApplyStepOffset(double offset);
extern void LCL_ApplyStepOffset(double offset);
/* Routine to invoke notify handlers on an unexpected time jump
in system clock */
extern void LCL_NotifyExternalTimeStep(struct timespec *raw, struct timespec *cooked,
extern void LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
double offset, double dispersion);
/* Routine to invoke notify handlers on leap second when the system clock
doesn't correct itself */
extern void LCL_NotifyLeap(int leap);
/* Perform the combination of modifying the frequency and applying
a slew, in one easy step */
extern int LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
/* Same as the routine above, except it does not call the registered
parameter change handlers */
extern int LCL_AccumulateFrequencyAndOffsetNoHandlers(double dfreq, double doffset,
double corr_rate);
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);
@@ -202,18 +194,10 @@ extern void LCL_Finalise(void);
to a timezone problem. */
extern int LCL_MakeStep(void);
/* Routine to cancel the outstanding system clock correction */
extern void LCL_CancelOffsetCorrection(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 schedule a leap second. Leap second will be inserted
at the end of the day if argument is positive, deleted if negative,
and zero cancels scheduled leap second. */
extern void LCL_SetLeap(int leap);
/* Routine to set a frequency correction (in ppm) that should be applied
to local clock to compensate for temperature changes. A positive
@@ -222,8 +206,4 @@ extern void LCL_SetSystemLeap(int leap, int tai_offset);
due to clamping or rounding). */
extern double LCL_SetTempComp(double comp);
/* Routine to update the synchronisation status in the kernel to allow other
applications to know if the system clock is synchronised and error bounds */
extern void LCL_SetSyncStatus(int synchronised, double est_error, double max_error);
#endif /* GOT_LOCAL_H */

View File

@@ -47,18 +47,15 @@ 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);
typedef void (*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);
typedef void (*lcl_OffsetCorrectionDriver)(struct timeval *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);
/* System driver to schedule leap second */
typedef void (*lcl_SetLeapDriver)(int leap);
extern void lcl_InvokeDispersionNotifyHandlers(double dispersion);
@@ -68,7 +65,6 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert,
lcl_SetLeapDriver set_leap,
lcl_SetSyncStatusDriver set_sync_status);
lcl_SetLeapDriver set_leap);
#endif /* GOT_LOCALP_H */

278
logging.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011-2014, 2018-2020
* 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
@@ -29,29 +29,30 @@
#include "sysincl.h"
#include <syslog.h>
#include "conf.h"
#include "logging.h"
#include "memory.h"
#include "mkdirpp.h"
#include "util.h"
/* This is used by DEBUG_LOG macro */
LOG_Severity log_min_severity = LOGS_INFO;
/* Current logging contexts */
static LOG_Context log_contexts;
int log_debug_enabled = 0;
/* ================================================== */
/* Flag indicating we have initialised */
static int initialised = 0;
static char *file_log_path = NULL;
static FILE *file_log = NULL;
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;
#ifdef WINNT
static FILE *logfile;
#endif
struct LogFile {
const char *name;
const char *banner;
@@ -66,20 +67,17 @@ static int n_filelogs = 0;
static struct LogFile logfiles[MAX_FILELOGS];
/* Global prefix for debug messages */
static char *debug_prefix;
/* ================================================== */
/* Init function */
void
LOG_Initialise(void)
{
debug_prefix = Strdup("");
log_contexts = 0;
initialised = 1;
LOG_OpenFileLog(NULL);
#ifdef WINNT
logfile = fopen("./chronyd.err", "a");
#endif
}
/* ================================================== */
@@ -88,19 +86,18 @@ LOG_Initialise(void)
void
LOG_Finalise(void)
{
if (system_log)
#ifdef WINNT
if (logfile) {
fclose(logfile);
}
#else
if (system_log) {
closelog();
if (file_log && file_log != stderr)
fclose(file_log);
file_log = NULL;
Free(file_log_path);
file_log_path = NULL;
}
#endif
LOG_CycleLogFiles();
Free(debug_prefix);
initialised = 0;
}
@@ -108,6 +105,11 @@ LOG_Finalise(void)
static void log_message(int fatal, LOG_Severity severity, const char *message)
{
#ifdef WINNT
if (logfile) {
fprintf(logfile, fatal ? "Fatal error : %s\n" : "%s\n", message);
}
#else
if (system_log) {
int priority;
switch (severity) {
@@ -130,45 +132,35 @@ static void log_message(int fatal, LOG_Severity severity, const char *message)
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);
} else {
fprintf(stderr, fatal ? "Fatal error : %s\n" : "%s\n", message);
}
#endif
}
/* ================================================== */
void LOG_Message(LOG_Severity severity,
#if DEBUG > 0
int line_number, const char *filename, const char *function_name,
#endif
const char *format, ...)
void LOG_Message(LOG_Severity severity, LOG_Facility facility,
int line_number, const char *filename,
const char *function_name, const char *format, ...)
{
char buf[2048];
va_list other_args;
time_t t;
struct tm *tm;
struct tm stm;
assert(initialised);
severity = CLAMP(LOGS_DEBUG, severity, LOGS_FATAL);
if (!system_log && file_log && severity >= log_min_severity) {
#ifdef WINNT
#else
if (!system_log) {
/* Don't clutter up syslog with timestamps and internal debugging info */
time(&t);
tm = gmtime(&t);
if (tm) {
strftime(buf, sizeof (buf), "%Y-%m-%dT%H:%M:%SZ", tm);
fprintf(file_log, "%s ", buf);
}
#if DEBUG > 0
if (log_min_severity <= LOGS_DEBUG) {
/* Log severity to character mapping (debug, info, warn, err, fatal) */
const char severity_chars[LOGS_FATAL - LOGS_DEBUG + 1] = {'D', 'I', 'W', 'E', 'F'};
fprintf(file_log, "%c:%s%s:%d:(%s) ", severity_chars[severity - LOGS_DEBUG],
debug_prefix, filename, line_number, function_name);
}
#endif
stm = *gmtime(&t);
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &stm);
fprintf(stderr, "%s ", buf);
if (debug_level >= DEBUG_LEVEL_PRINT_FUNCTION)
fprintf(stderr, "%s:%d:(%s) ", filename, line_number, function_name);
}
#endif
va_start(other_args, format);
vsnprintf(buf, sizeof(buf), format, other_args);
@@ -179,23 +171,22 @@ void LOG_Message(LOG_Severity severity,
case LOGS_INFO:
case LOGS_WARN:
case LOGS_ERR:
if (severity >= log_min_severity)
log_message(0, severity, buf);
log_message(0, severity, buf);
break;
case LOGS_FATAL:
if (severity >= log_min_severity)
log_message(1, severity, buf);
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 (!LOG_NotifyParent(buf))
; /* Not much we can do here */
} else if (system_log && parent_fd == 0) {
system_log = 0;
log_message(1, severity, buf);
/* With syslog, send the message also to the grandparent
process or write it to stderr if not detached */
if (system_log) {
if (parent_fd > 0) {
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
; /* Not much we can do here */
} else if (parent_fd == 0) {
system_log = 0;
log_message(1, severity, buf);
}
}
exit(1);
break;
default:
assert(0);
@@ -204,98 +195,26 @@ void LOG_Message(LOG_Severity severity,
/* ================================================== */
static FILE *
open_file_log(const char *log_file, char mode)
{
FILE *f;
if (log_file) {
f = UTI_OpenFile(NULL, log_file, NULL, mode, 0640);
} else {
f = stderr;
}
/* Enable line buffering */
if (f)
setvbuf(f, NULL, _IOLBF, BUFSIZ);
return f;
}
/* ================================================== */
void
LOG_OpenFileLog(const char *log_file)
{
if (file_log_path)
Free(file_log_path);
if (log_file)
file_log_path = Strdup(log_file);
else
file_log_path = NULL;
if (file_log && file_log != stderr)
fclose(file_log);
file_log = open_file_log(file_log_path, 'A');
}
/* ================================================== */
void
LOG_OpenSystemLog(void)
{
#ifdef WINNT
#else
system_log = 1;
openlog("chronyd", LOG_PID, LOG_DAEMON);
#endif
}
/* ================================================== */
void LOG_SetMinSeverity(LOG_Severity severity)
void LOG_SetDebugLevel(int level)
{
/* Don't print any debug messages in a non-debug build */
log_min_severity = CLAMP(DEBUG > 0 ? LOGS_DEBUG : LOGS_INFO, severity, LOGS_FATAL);
}
/* ================================================== */
LOG_Severity
LOG_GetMinSeverity(void)
{
return log_min_severity;
}
/* ================================================== */
void
LOG_SetContext(LOG_Context context)
{
log_contexts |= context;
}
/* ================================================== */
void
LOG_UnsetContext(LOG_Context context)
{
log_contexts &= ~context;
}
/* ================================================== */
LOG_Severity
LOG_GetContextSeverity(LOG_Context contexts)
{
return log_contexts & contexts ? LOGS_INFO : LOGS_DEBUG;
}
/* ================================================== */
void
LOG_SetDebugPrefix(const char *prefix)
{
Free(debug_prefix);
debug_prefix = Strdup(prefix);
debug_level = level;
if (level >= DEBUG_LEVEL_PRINT_DEBUG) {
if (!DEBUG)
LOG(LOGS_WARN, LOGF_Logging, "Not compiled with full debugging support");
log_debug_enabled = 1;
}
}
/* ================================================== */
@@ -304,19 +223,6 @@ void
LOG_SetParentFd(int fd)
{
parent_fd = fd;
if (file_log == stderr)
file_log = NULL;
}
/* ================================================== */
int
LOG_NotifyParent(const char *message)
{
if (parent_fd <= 0)
return 1;
return write(parent_fd, message, strlen(message) + 1) > 0;
}
/* ================================================== */
@@ -334,10 +240,7 @@ LOG_CloseParentFd()
LOG_FileID
LOG_FileOpen(const char *name, const char *banner)
{
if (n_filelogs >= MAX_FILELOGS) {
assert(0);
return -1;
}
assert(n_filelogs < MAX_FILELOGS);
logfiles[n_filelogs].name = name;
logfiles[n_filelogs].banner = banner;
@@ -359,20 +262,18 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
return;
if (!logfiles[id].file) {
char *logdir = CNF_GetLogDir();
char filename[512];
if (!logdir) {
LOG(LOGS_WARN, "logdir not specified");
if (snprintf(filename, sizeof(filename), "%s/%s.log",
CNF_GetLogDir(), logfiles[id].name) >= sizeof(filename) ||
!(logfiles[id].file = fopen(filename, "a"))) {
LOG(LOGS_WARN, LOGF_Refclock, "Couldn't open logfile %s for update", filename);
logfiles[id].name = NULL;
return;
}
logfiles[id].file = UTI_OpenFile(logdir, logfiles[id].name, ".log", 'a', 0644);
if (!logfiles[id].file) {
/* Disable the log */
logfiles[id].name = NULL;
return;
}
/* Close on exec */
UTI_FdSetCloexec(fileno(logfiles[id].file));
}
banner = CNF_GetLogBanner();
@@ -380,7 +281,7 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
char bannerline[256];
int i, bannerlen;
bannerlen = MIN(strlen(logfiles[id].banner), sizeof (bannerline) - 1);
bannerlen = strlen(logfiles[id].banner);
for (i = 0; i < bannerlen; i++)
bannerline[i] = '=';
@@ -401,32 +302,31 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
/* ================================================== */
void
LOG_CreateLogFileDir(void)
{
const char *logdir;
logdir = CNF_GetLogDir();
if (!mkdir_and_parents(logdir)) {
LOG(LOGS_ERR, LOGF_Logging, "Could not create directory %s", logdir);
}
}
/* ================================================== */
void
LOG_CycleLogFiles(void)
{
struct stat st;
LOG_FileID i;
FILE *f;
/* The log will be opened later when an entry is logged */
for (i = 0; i < n_filelogs; i++) {
if (logfiles[i].file)
fclose(logfiles[i].file);
logfiles[i].file = NULL;
logfiles[i].writes = 0;
}
/* Try to open the log specified by the -l option, but only if nothing is
present at its path to avoid unnecessary error messages. Keep the
original file if that fails (the process might no longer have the
necessary privileges to write in the directory). */
if (file_log && file_log != stderr && stat(file_log_path, &st) < 0 && errno == ENOENT) {
f = open_file_log(file_log_path, 'a');
if (f) {
fclose(file_log);
file_log = f;
}
}
}
/* ================================================== */

119
logging.h
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2013-2015
* 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
@@ -31,6 +31,9 @@
#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. */
@@ -42,39 +45,62 @@
#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(...) \
#define DEBUG_LOG(facility, ...) \
do { \
if (DEBUG && log_min_severity == LOGS_DEBUG) \
LOG_MESSAGE(LOGS_DEBUG, __VA_ARGS__); \
if (DEBUG && log_debug_enabled) \
LOG_Message(LOGS_DEBUG, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
} while (0)
#define LOG_FATAL(...) \
#define LOG(severity, facility, ...) LOG_Message(severity, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
#define LOG_FATAL(facility, ...) \
do { \
LOG_MESSAGE(LOGS_FATAL, __VA_ARGS__); \
LOG_Message(LOGS_FATAL, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
exit(1); \
} while (0)
#define LOG(severity, ...) LOG_MESSAGE(severity, __VA_ARGS__)
/* Definition of severity */
typedef enum {
LOGS_DEBUG = -1,
LOGS_INFO = 0,
LOGS_INFO,
LOGS_WARN,
LOGS_ERR,
LOGS_FATAL,
LOGS_DEBUG
} LOG_Severity;
/* Minimum severity of messages to be logged */
extern LOG_Severity log_min_severity;
/* Definition of facility. Each message is tagged with who generated
it, so that the user can customise what level of reporting he gets
for each area of the software */
typedef enum {
LOGF_Reference,
LOGF_NtpIO,
LOGF_NtpCore,
LOGF_NtpSources,
LOGF_Scheduler,
LOGF_SourceStats,
LOGF_Sources,
LOGF_Local,
LOGF_Util,
LOGF_Main,
LOGF_ClientLog,
LOGF_Configure,
LOGF_CmdMon,
LOGF_Acquire,
LOGF_Manual,
LOGF_Keys,
LOGF_Logging,
LOGF_Nameserv,
LOGF_Rtc,
LOGF_Regress,
LOGF_Sys,
LOGF_SysGeneric,
LOGF_SysLinux,
LOGF_SysNetBSD,
LOGF_SysSolaris,
LOGF_SysSunOS,
LOGF_SysWinnt,
LOGF_TempComp,
LOGF_RtcLinux,
LOGF_Refclock
} LOG_Facility;
/* Init function */
extern void LOG_Initialise(void);
@@ -83,53 +109,25 @@ extern void LOG_Initialise(void);
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,
FORMAT_ATTRIBUTE_PRINTF(6, 7)
extern void LOG_Message(LOG_Severity severity, LOG_Facility facility,
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 the minimum severity of a message to be logged or printed to terminal.
If the severity is LOGS_DEBUG and DEBUG is enabled, all messages will be
prefixed with the filename, line number, and function name. */
extern void LOG_SetMinSeverity(LOG_Severity severity);
/* Get the minimum severity */
extern LOG_Severity LOG_GetMinSeverity(void);
/* Flags for info messages that should be logged only in specific contexts */
typedef enum {
LOGC_Command = 1,
LOGC_SourceFile = 2,
} LOG_Context;
/* Modify current contexts */
extern void LOG_SetContext(LOG_Context context);
extern void LOG_UnsetContext(LOG_Context context);
/* Get severity depending on the current active contexts: INFO if they contain
at least one of the specified contexts, DEBUG otherwise */
extern LOG_Severity LOG_GetContextSeverity(LOG_Context contexts);
/* Set a prefix for debug messages */
extern void LOG_SetDebugPrefix(const char *prefix);
/* Log messages to a file instead of stderr, or stderr again if NULL */
extern void LOG_OpenFileLog(const char *log_file);
/* 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 syslog instead of stderr */
extern void LOG_OpenSystemLog(void);
/* Stop using stderr and send fatal message to the foreground process */
/* Send fatal message also to the foreground process */
extern void LOG_SetParentFd(int fd);
/* Send a message to the foreground process */
extern int LOG_NotifyParent(const char *message);
/* Close the pipe to the foreground process */
/* Close the pipe to the foreground process so it can exit */
extern void LOG_CloseParentFd(void);
/* File logging functions */
@@ -141,6 +139,7 @@ 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_CreateLogFileDir(void);
extern void LOG_CycleLogFiles(void);
#endif /* GOT_LOGGING_H */

548
main.c
View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2012-2020
* 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
@@ -32,16 +32,11 @@
#include "main.h"
#include "sched.h"
#include "leapdb.h"
#include "local.h"
#include "sys.h"
#include "ntp_io.h"
#include "ntp_signd.h"
#include "ntp_sources.h"
#include "ntp_core.h"
#include "nts_ke_server.h"
#include "nts_ntp_server.h"
#include "socket.h"
#include "sources.h"
#include "sourcestats.h"
#include "reference.h"
@@ -53,11 +48,9 @@
#include "rtc.h"
#include "refclock.h"
#include "clientlog.h"
#include "broadcast.h"
#include "nameserv.h"
#include "privops.h"
#include "smooth.h"
#include "tempcomp.h"
#include "util.h"
/* ================================================== */
@@ -74,62 +67,12 @@ static REF_Mode ref_mode = REF_ModeNormal;
/* ================================================== */
static void
do_platform_checks(void)
{
struct timespec ts;
/* 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);
/* Require time_t and tv_nsec in timespec to be signed */
ts.tv_sec = -1;
ts.tv_nsec = -1;
assert(ts.tv_sec < 0 && ts.tv_nsec < 0);
}
/* ================================================== */
static void
delete_pidfile(void)
{
const char *pidfile = CNF_GetPidFile();
if (!pidfile)
return;
if (!UTI_RemoveFile(NULL, pidfile, NULL))
;
}
/* ================================================== */
static void
notify_system_manager(int start)
{
#ifdef LINUX
/* The systemd protocol is documented in the sd_notify(3) man page */
const char *message, *path = getenv("NOTIFY_SOCKET");
int sock_fd;
if (!path)
return;
if (path[0] != '/')
LOG_FATAL("Unsupported notification socket");
message = start ? "READY=1" : "STOPPING=1";
sock_fd = SCK_OpenUnixDatagramSocket(path, NULL, 0);
if (sock_fd < 0 || SCK_Send(sock_fd, message, strlen(message), 0) != strlen(message))
LOG_FATAL("Could not send notification to $NOTIFY_SOCKET");
SCK_CloseSocket(sock_fd);
#endif
/* Don't care if this fails, there's not a lot we can do */
unlink(pidfile);
}
/* ================================================== */
@@ -139,48 +82,32 @@ MAI_CleanupAndExit(void)
{
if (!initialised) exit(exit_status);
notify_system_manager(0);
if (CNF_GetDumpOnExit()) {
SRC_DumpSources();
}
LCL_CancelOffsetCorrection();
SRC_DumpSources();
/* Don't update clock when removing sources */
REF_SetMode(REF_ModeIgnore);
SMT_Finalise();
TMC_Finalise();
MNL_Finalise();
CLG_Finalise();
NKS_Finalise();
NNS_Finalise();
NSD_Finalise();
NSR_Finalise();
SST_Finalise();
NCR_Finalise();
NIO_Finalise();
CAM_Finalise();
BRD_Finalise();
SST_Finalise();
REF_Finalise();
KEY_Finalise();
RCL_Finalise();
SRC_Finalise();
REF_Finalise();
LDB_Finalise();
RTC_Finalise();
CAM_Finalise();
NIO_Finalise();
SYS_Finalise();
SCK_Finalise();
SCH_Finalise();
LCL_Finalise();
PRV_Finalise();
delete_pidfile();
CNF_Finalise();
HSH_Finalise();
LOG_Finalise();
UTI_ResetGetRandomFunctions();
exit(exit_status);
}
@@ -189,18 +116,7 @@ MAI_CleanupAndExit(void)
static void
signal_cleanup(int x)
{
SCH_QuitProgram();
}
/* ================================================== */
static void
quit_timeout(void *arg)
{
LOG(LOGS_INFO, "Timeout reached");
/* Return with non-zero status if the clock is not synchronised */
exit_status = REF_GetOurStratum() >= NTP_MAX_STRATUM;
if (!initialised) exit(0);
SCH_QuitProgram();
}
@@ -219,14 +135,13 @@ ntp_source_resolving_end(void)
SRC_ReloadSources();
}
SRC_RemoveDumpFiles();
RTC_StartMeasurements();
RCL_StartRefclocks();
NSR_StartSources();
NSR_AutoStartSources();
/* Special modes can end only when sources update their reachability.
Give up immediately if there are no active sources. */
Give up immediatelly if there are no active sources. */
if (ref_mode != REF_ModeNormal && !SRC_ActiveSources()) {
REF_SetUnsynchronised();
}
@@ -244,12 +159,7 @@ post_init_ntp_hook(void *anything)
REF_SetMode(ref_mode);
}
notify_system_manager(1);
/* Send an empty message to the foreground process so it can exit.
If that fails, indicating the process was killed, exit too. */
if (!LOG_NotifyParent(""))
SCH_QuitProgram();
/* Close the pipe to the foreground process so it can exit */
LOG_CloseParentFd();
CNF_AddSources();
@@ -298,185 +208,131 @@ post_init_rtc_hook(void *anything)
}
/* ================================================== */
/* Return 1 if the process exists on the system. */
static void
check_pidfile(void)
static int
does_process_exist(int pid)
{
int status;
status = getsid(pid);
if (status >= 0) {
return 1;
} else {
return 0;
}
}
/* ================================================== */
static int
maybe_another_chronyd_running(int *other_pid)
{
const char *pidfile = CNF_GetPidFile();
FILE *in;
int pid, count;
if (!pidfile)
return;
*other_pid = 0;
in = UTI_OpenFile(NULL, pidfile, NULL, 'r', 0);
if (!in)
return;
in = fopen(pidfile, "r");
if (!in) return 0;
count = fscanf(in, "%d", &pid);
fclose(in);
if (count != 1)
return;
if (count != 1) return 0;
if (getsid(pid) < 0)
return;
LOG_FATAL("Another chronyd may already be running (pid=%d), check %s",
pid, pidfile);
*other_pid = pid;
return does_process_exist(pid);
}
/* ================================================== */
static void
write_pidfile(void)
write_lockfile(void)
{
const char *pidfile = CNF_GetPidFile();
FILE *out;
if (!pidfile)
return;
out = UTI_OpenFile(NULL, pidfile, NULL, 'W', 0644);
fprintf(out, "%d\n", (int)getpid());
fclose(out);
out = fopen(pidfile, "w");
if (!out) {
LOG_FATAL(LOGF_Main, "could not open lockfile %s for writing", pidfile);
} else {
fprintf(out, "%d\n", getpid());
fclose(out);
}
}
/* ================================================== */
#define DEV_NULL "/dev/null"
static void
go_daemon(void)
{
#ifdef WINNT
#else
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));
LOG_FATAL(LOGF_Logging, "Could not detach, pipe failed : %s", strerror(errno));
}
/* Does this preserve existing signal handlers? */
pid = fork();
if (pid < 0) {
LOG_FATAL("fork() failed : %s", strerror(errno));
LOG_FATAL(LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
} else if (pid > 0) {
/* In the 'grandparent' */
char message[1024];
int r;
/* Don't exit before the 'parent' */
waitpid(pid, NULL, 0);
r = read(pipefd[0], message, sizeof (message));
close(pipefd[0]);
close(pipefd[1]);
if (r != 1 || message[0] != '\0') {
if (r > 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);
fprintf(stderr, "%.1024s\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));
LOG_FATAL(LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
} else if (pid > 0) {
/* In the 'parent' */
close(pipefd[0]);
close(pipefd[1]);
exit(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));
LOG_FATAL(LOGF_Logging, "Could not chdir to / : %s", strerror(errno));
}
/* Don't keep stdin/out/err from before. But don't close
the parent pipe yet, or reusable file descriptors. */
the parent pipe yet. */
for (fd=0; fd<1024; fd++) {
if (fd != pipefd[1] && !SCK_IsReusable(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 [OPTION]... [DIRECTIVE]...\n\n"
"Options:\n"
" -4\t\tUse IPv4 addresses only\n"
" -6\t\tUse IPv6 addresses only\n"
" -f FILE\tSpecify configuration file (%s)\n"
" -n\t\tDon't run as daemon\n"
" -d\t\tDon't run as daemon and log to stderr\n"
#if DEBUG > 0
" -d -d\t\tEnable debug messages\n"
#endif
" -l FILE\tLog to file\n"
" -L LEVEL\tSet logging threshold (0)\n"
" -p\t\tPrint configuration and exit\n"
" -q\t\tSet clock and exit\n"
" -Q\t\tLog offset and exit\n"
" -r\t\tReload dump files\n"
" -R\t\tAdapt configuration for restart\n"
" -s\t\tSet clock from RTC\n"
" -t SECONDS\tExit after elapsed time\n"
" -u USER\tSpecify user (%s)\n"
" -U\t\tDon't check for root\n"
" -F LEVEL\tSet system call filter level (0)\n"
" -P PRIORITY\tSet process priority (0)\n"
" -m\t\tLock memory\n"
" -x\t\tDon't control clock\n"
" -v, --version\tPrint version and exit\n"
" -h, --help\tPrint usage and exit\n",
progname, DEFAULT_CONF_FILE, DEFAULT_USER);
}
/* ================================================== */
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;
}
/* ================================================== */
@@ -485,191 +341,127 @@ 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 = -1;
int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
int clock_control = 1, system_log = 1, log_severity = LOGS_INFO;
int user_check = 1, config_args = 0, print_config = 0;
do_platform_checks();
char *user = NULL;
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
int do_init_rtc = 0, restarted = 0;
int other_pid;
int lock_memory = 0, sched_priority = 0;
int system_log = 1;
int config_args = 0;
LOG_Initialise();
/* Parse 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;
/* Parse command line options */
while (++argv, (--argc)>0) {
if (!strcmp("-f", *argv)) {
++argv, --argc;
conf_file = *argv;
} else if (!strcmp("-P", *argv)) {
++argv, --argc;
if (argc == 0 || sscanf(*argv, "%d", &sched_priority) != 1) {
LOG_FATAL(LOGF_Main, "Bad scheduler priority");
}
} else if (!strcmp("-m", *argv)) {
lock_memory = 1;
} else if (!strcmp("-r", *argv)) {
reload = 1;
} else if (!strcmp("-R", *argv)) {
restarted = 1;
} else if (!strcmp("-u", *argv)) {
++argv, --argc;
if (argc == 0) {
LOG_FATAL(LOGF_Main, "Missing user name");
} else {
user = *argv;
}
} else if (!strcmp("-s", *argv)) {
do_init_rtc = 1;
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
printf("chronyd (chrony) version %s\n", CHRONY_VERSION);
exit(0);
} else if (!strcmp("-n", *argv)) {
nofork = 1;
} else if (!strcmp("-d", *argv)) {
debug++;
nofork = 1;
system_log = 0;
} else if (!strcmp("-q", *argv)) {
ref_mode = REF_ModeUpdateOnce;
nofork = 1;
system_log = 0;
} else if (!strcmp("-Q", *argv)) {
ref_mode = REF_ModePrintOnce;
nofork = 1;
system_log = 0;
} else if (!strcmp("-4", *argv)) {
address_family = IPADDR_INET4;
} else if (!strcmp("-6", *argv)) {
address_family = IPADDR_INET6;
} else if (*argv[0] == '-') {
LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
} else {
/* Process remaining arguments and configuration lines */
config_args = argc;
break;
}
}
optind = 1;
/* Parse short command-line options */
while ((opt = getopt(argc, argv, "46df:F:hl:L:mnpP:qQrRst:u:Uvx")) != -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 'L':
log_severity = parse_int_arg(optarg);
break;
case 'm':
lock_memory = 1;
break;
case 'n':
nofork = 1;
break;
case 'p':
print_config = 1;
user_check = 0;
nofork = 1;
system_log = 0;
log_severity = LOGS_WARN;
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;
user_check = 0;
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 'U':
user_check = 0;
break;
case 'v':
print_version();
return 0;
case 'x':
clock_control = 0;
break;
default:
print_help(progname);
return opt != 'h';
}
if (getuid() != 0) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
fprintf(stderr,"Not superuser\n");
exit(1);
}
if (user_check && getuid() != 0)
LOG_FATAL("Not superuser");
/* Initialise reusable file descriptors before fork */
SCK_PreInitialise();
/* Turn into a daemon */
if (!nofork) {
go_daemon();
}
if (log_file) {
LOG_OpenFileLog(log_file);
} else if (system_log) {
if (system_log) {
LOG_OpenSystemLog();
}
LOG_SetMinSeverity(debug >= 2 ? LOGS_DEBUG : log_severity);
LOG_SetDebugLevel(debug);
LOG(LOGS_INFO, "chronyd version %s starting (%s)", CHRONY_VERSION, CHRONYD_FEATURES);
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting", CHRONY_VERSION);
DNS_SetAddressFamily(address_family);
CNF_Initialise(restarted, client_only);
if (print_config)
CNF_EnablePrint();
CNF_SetRestarted(restarted);
/* 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]);
do {
CNF_ParseLine(NULL, config_args - argc + 1, *argv);
} while (++argv, --argc);
}
if (print_config)
return 0;
/* Check whether another chronyd may already be running. Do this after
* forking, so that message logging goes to the right place (i.e. syslog), in
* case this chronyd is being run from a boot script. */
if (maybe_another_chronyd_running(&other_pid)) {
LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
other_pid, CNF_GetPidFile());
}
/* Check whether another chronyd may already be running */
check_pidfile();
/* Write our lockfile to prevent other chronyds running. This has *GOT* to
* be done *AFTER* the daemon-creation fork() */
write_lockfile();
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);
/* Write our pidfile to prevent other instances from running */
write_pidfile();
PRV_Initialise();
LCL_Initialise();
SCH_Initialise();
SCK_Initialise(address_family);
/* Start helper processes if needed */
NKS_PreInitialise(pw->pw_uid, pw->pw_gid, scfilter_level);
SYS_Initialise(clock_control);
SYS_Initialise();
NIO_Initialise(address_family);
CAM_Initialise(address_family);
RTC_Initialise(do_init_rtc);
SRC_Initialise();
RCL_Initialise();
KEY_Initialise();
/* Open privileged ports before dropping root */
CAM_Initialise();
NIO_Initialise();
NCR_Initialise();
CNF_SetupAccessRestrictions();
/* Command-line switch must have priority */
if (!sched_priority) {
sched_priority = CNF_GetSchedPriority();
@@ -682,38 +474,28 @@ int main
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, SYS_MAIN_PROCESS);
/* Warn if missing read access or having write access to keys */
CNF_CheckReadOnlyAccess();
if (!user) {
user = CNF_GetUser();
}
if (user && strcmp(user, "root")) {
SYS_DropRoot(user);
}
if (!geteuid())
LOG(LOGS_WARN, "Running with root privileges");
LOG_CreateLogFileDir();
LDB_Initialise();
REF_Initialise();
SST_Initialise();
BRD_Initialise();
NCR_Initialise();
NSR_Initialise();
NSD_Initialise();
NNS_Initialise();
NKS_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, 1);
CAM_OpenUnixSocket();
if (scfilter_level)
SYS_EnableSystemCallFilter(scfilter_level, SYS_MAIN_PROCESS);
CNF_SetupAccessRestrictions();
if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) {
ref_mode = REF_ModeInitStepSlew;
@@ -722,20 +504,24 @@ int main
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);
}
signal(SIGINT, signal_cleanup);
signal(SIGTERM, signal_cleanup);
#if !defined(WINNT)
signal(SIGQUIT, signal_cleanup);
signal(SIGHUP, signal_cleanup);
#endif /* WINNT */
/* The program normally runs under control of the main loop in
the scheduler. */
SCH_MainLoop();
LOG(LOGS_INFO, "chronyd exiting");
LOG(LOGS_INFO, LOGF_Main, "chronyd exiting");
MAI_CleanupAndExit();

View File

@@ -1,6 +1,6 @@
#!/bin/sh
LANG=C.UTF-8
LANG=C
export LANG
if [ $# -ne 1 ]; then
@@ -11,6 +11,7 @@ fi
version=$1
tag=$version
subdir=chrony-${version}
mandate=$(date +'%B %Y')
umask 022
@@ -36,13 +37,39 @@ cd RELEASES/$subdir || exit 1
echo $version > version.txt
./configure && make -C doc man txt || exit 1
sed -i -e "s%@@VERSION@@%${version}%" examples/chrony.spec
iconv -f utf-8 -t ascii//TRANSLIT < doc/installation.txt > INSTALL
iconv -f utf-8 -t ascii//TRANSLIT < doc/faq.txt > FAQ
for m in chrony.1 chronyc.1.in chrony.conf.5.in chronyd.8.in; do
sed -e "s%@VERSION@%${version}%;s%@MAN_DATE@%${mandate}%" \
< $m > ${m}_
mv -f ${m}_ $m
done
./configure && make chrony.txt || exit 1
mv chrony.txt chrony.txt_
make distclean
rm -f make_release .gitignore
mv chrony.txt_ chrony.txt
awk '/^[1-9] Installation$/{p=1}
/^[1-9]\.. Support for line editing/{exit}; p' chrony.txt | \
tail -n +4 > INSTALL
if [ $(wc -l < INSTALL) -gt 100 -o $(wc -l < INSTALL) -lt 85 ]; then
echo "INSTALL generated incorrectly?"
exit 3
fi
awk '/^[1-9] Frequently asked questions$/{p=1}
/^Appendix A GNU General Public License$/{exit}; p' chrony.txt | \
tail -n +4 | sed 's/^[1-9]\.\([1-9]\)/\1/' | sed 's/^----/--/' | \
sed 's/^====/==/' > FAQ
if [ $(wc -l < FAQ) -gt 400 -o $(wc -l < FAQ) -lt 200 ]; then
echo "FAQ generated incorrectly?"
exit 3
fi
rm -f config.h config.log make_release .gitignore
cd ..
tar cv --owner root --group root $subdir | gzip -9 > ${subdir}.tar.gz

View File

@@ -47,15 +47,13 @@ static int enabled = 0;
/* More recent samples at highest indices */
typedef struct {
struct timespec when; /* This is our 'cooked' time */
struct timeval 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];
@@ -64,8 +62,8 @@ static int n_samples;
/* ================================================== */
static void
slew_samples(struct timespec *raw,
struct timespec *cooked,
slew_samples(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double doffset,
LCL_ChangeType change_type,
@@ -92,14 +90,12 @@ MNL_Initialise(void)
void
MNL_Finalise(void)
{
LCL_RemoveParameterChangeHandler(slew_samples, NULL);
}
/* ================================================== */
static void
estimate_and_set_system(struct timespec *now, int offset_provided, double offset,
double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm)
estimate_and_set_system(struct timeval *now, int offset_provided, double offset, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
{
double agos[MAX_SAMPLES], offsets[MAX_SAMPLES];
double b0, b1;
@@ -110,26 +106,32 @@ estimate_and_set_system(struct timespec *now, int offset_provided, double offset
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);
UTI_DiffTimevalsToDouble(&agos[i], &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;
}
RGR_FindBestRobustRegression(agos, offsets, n_samples,
1.0e-8, /* 0.01ppm easily good enough for this! */
&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 {
if (offset_provided) {
b0 = offset;
} else {
b0 = 0.0;
}
b1 = freq = 0.0;
found_freq = 0;
agos[0] = 0.0;
offsets[0] = b0;
}
@@ -141,20 +143,21 @@ estimate_and_set_system(struct timespec *now, int offset_provided, double offset
}
if (found_freq) {
LOG(LOGS_INFO, "Making a frequency change of %.3f ppm and a slew of %.6f",
LOG(LOGS_INFO, LOGF_Manual,
"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);
LOG(LOGS_INFO, LOGF_Manual, "Making a slew of %.6f", slew_by);
REF_SetManualReference(now,
slew_by,
0.0, skew);
}
if (reg_offset) *reg_offset = b0;
if (offset_cs) *offset_cs = (long)(0.5 + 100.0 * b0);
if (dfreq_ppm) *dfreq_ppm = 1.0e6 * freq;
if (new_afreq_ppm) *new_afreq_ppm = LCL_ReadAbsoluteFrequency();
@@ -168,28 +171,18 @@ estimate_and_set_system(struct timespec *now, int offset_provided, double offset
/* ================================================== */
int
MNL_AcceptTimestamp(struct timespec *ts, double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm)
MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
{
struct timespec now;
double offset, diff;
struct timeval now;
double offset;
int i;
if (enabled) {
/* Check whether timestamp is within margin of old one */
LCL_ReadCookedTime(&now, NULL);
/* Make sure the provided timestamp is sane and the sample
is not too close to the last one */
if (!UTI_IsTimeOffsetSane(ts, 0.0))
return 0;
if (n_samples) {
diff = UTI_DiffTimespecsToDouble(&now, &samples[n_samples - 1].when);
if (diff < MIN_SAMPLE_SEPARATION)
return 0;
}
offset = UTI_DiffTimespecsToDouble(&now, ts);
UTI_DiffTimevalsToDouble(&offset, &now, ts);
/* Check if buffer full up */
if (n_samples == MAX_SAMPLES) {
@@ -205,7 +198,7 @@ MNL_AcceptTimestamp(struct timespec *ts, double *reg_offset, double *dfreq_ppm,
samples[n_samples].orig_offset = offset;
++n_samples;
estimate_and_set_system(&now, 1, offset, reg_offset, dfreq_ppm, new_afreq_ppm);
estimate_and_set_system(&now, 1, offset, offset_cs, dfreq_ppm, new_afreq_ppm);
return 1;
@@ -219,8 +212,8 @@ MNL_AcceptTimestamp(struct timespec *ts, double *reg_offset, double *dfreq_ppm,
/* ================================================== */
static void
slew_samples(struct timespec *raw,
struct timespec *cooked,
slew_samples(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double doffset,
LCL_ChangeType change_type,
@@ -234,7 +227,7 @@ slew_samples(struct timespec *raw,
}
for (i=0; i<n_samples; i++) {
UTI_AdjustTimespec(&samples[i].when, cooked, &samples[i].when, &delta_time,
UTI_AdjustTimeval(&samples[i].when, cooked, &samples[i].when, &delta_time,
dfreq, doffset);
samples[i].offset += delta_time;
}
@@ -265,14 +258,6 @@ MNL_Reset(void)
n_samples = 0;
}
/* ================================================== */
int
MNL_IsEnabled(void)
{
return enabled;
}
/* ================================================== */
/* Generate report data for the REQ_MANUAL_LIST command/monitoring
protocol */
@@ -304,7 +289,7 @@ int
MNL_DeleteSample(int index)
{
int i;
struct timespec now;
struct timeval now;
if ((index < 0) || (index >= n_samples)) {
return 0;

View File

@@ -33,12 +33,11 @@
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 int MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, 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);

15
md5.c
View File

@@ -117,7 +117,8 @@ inline UINT4 ROTATE_LEFT(UINT4 x, int n)
/* The routine MD5Init initializes the message-digest context
mdContext. All fields are set to zero.
*/
void MD5Init (MD5_CTX *mdContext)
void MD5Init (mdContext)
MD5_CTX *mdContext;
{
mdContext->i[0] = mdContext->i[1] = (UINT4)0;
@@ -133,7 +134,10 @@ void MD5Init (MD5_CTX *mdContext)
account for the presence of each of the characters inBuf[0..inLen-1]
in the message whose digest is being computed.
*/
void MD5Update (MD5_CTX *mdContext, unsigned const char *inBuf, unsigned int inLen)
void MD5Update (mdContext, inBuf, inLen)
MD5_CTX *mdContext;
unsigned const char *inBuf;
unsigned int inLen;
{
UINT4 in[16];
int mdi;
@@ -169,7 +173,8 @@ void MD5Update (MD5_CTX *mdContext, unsigned const char *inBuf, unsigned int inL
ends with the desired message digest in mdContext->digest[0...15].
*/
void MD5Final (MD5_CTX *mdContext)
void MD5Final (mdContext)
MD5_CTX *mdContext;
{
UINT4 in[16];
int mdi;
@@ -209,7 +214,9 @@ void MD5Final (MD5_CTX *mdContext)
/* Basic MD5 step. Transforms buf based on in.
*/
static void Transform (UINT4 *buf, UINT4 *in)
static void Transform (buf, in)
UINT4 *buf;
UINT4 *in;
{
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];

View File

@@ -1,98 +0,0 @@
/*
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;
if (size == 0) {
Free(ptr);
return NULL;
}
r = realloc(ptr, size);
if (!r)
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;
}

View File

@@ -27,19 +27,11 @@
#ifndef GOT_MEMORY_H
#define GOT_MEMORY_H
#include "sysincl.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 Malloc(x) malloc(x)
#define MallocNew(T) ((T *) malloc(sizeof(T)))
#define MallocArray(T, n) ((T *) malloc((n) * sizeof(T)))
#define Realloc(x,y) realloc(x,y)
#define ReallocArray(T,n,x) ((T *) realloc((void *)(x), (n)*sizeof(T)))
#define Free(x) free(x)
#endif /* GOT_MEMORY_H */

134
mkdirpp.c Normal file
View File

@@ -0,0 +1,134 @@
/*
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.
*
**********************************************************************
=======================================================================
A function for creating a directory and any parent directories that
don't exist.
*/
#include "config.h"
#include "sysincl.h"
#include "mkdirpp.h"
static int
do_dir(char *p)
{
int status;
struct stat buf;
#if defined(TEST)
fprintf(stderr, "do_dir(%s)\n", p);
#endif
/* See if directory exists */
status = stat(p, &buf);
if (status < 0) {
if (errno == ENOENT) {
/* Try to create directory */
status = mkdir(p, 0755);
return status;
} else {
return status;
}
}
if (!S_ISDIR(buf.st_mode)) {
return -1;
}
return 0;
}
/* ================================================== */
/* Return 0 if the directory couldn't be created, 1 if it could (or
already existed) */
int
mkdir_and_parents(const char *path)
{
char *p;
int len;
int i, j, k, last;
len = strlen(path);
p = (char *) malloc(1 + len);
i = k = 0;
while (1) {
p[i++] = path[k++];
if (path[k] == '/' || !path[k]) {
p[i] = 0;
if (do_dir(p) < 0) {
free(p);
return 0;
}
if (!path[k]) {
/* End of the string */
break;
}
/* check whether its a trailing / or group of / */
last = 1;
j = k+1;
while (path[j]) {
if (path[j] != '/') {
k = j - 1; /* Pick up a / into p[] thru the assignment at the top of the loop */
last = 0;
break;
}
j++;
}
if (last) {
break;
}
}
if (!path[k]) break;
}
free(p);
return 1;
}
/* ================================================== */
#if defined(TEST)
int main(int argc, char **argv) {
if (argc > 1) {
/* Invert sense of result */
return mkdir_and_parents(argv[1]) ? 0 : 1;
} else {
return 1;
}
}
#endif

View File

@@ -1,8 +1,8 @@
/*
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2025
* 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
@@ -21,8 +21,11 @@
=======================================================================
Header file for lists that are needed in seccomp filters but need to
be compiled separately from sys_linux.c due to conflicting headers.
*/
*/
extern unsigned long SYS_Linux_GetExtraScmpIoctl(int index);
#ifndef GOT_MKDIRPP_H
#define GOT_MKDIRPP_H
extern int mkdir_and_parents(const char *path);
#endif

View File

@@ -30,11 +30,7 @@
#include "sysincl.h"
#include <netdb.h>
#include <resolv.h>
#include "nameserv.h"
#include "socket.h"
#include "util.h"
/* ================================================== */
@@ -48,41 +44,15 @@ DNS_SetAddressFamily(int family)
}
DNS_Status
DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
DNS_Name2IPAddress(const char *name, IPAddr *addr)
{
#ifdef HAVE_GETADDRINFO
struct addrinfo hints, *res, *ai;
int i, result;
IPAddr ip;
max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
for (i = 0; i < max_addrs; i++)
ip_addrs[i].family = IPADDR_UNSPEC;
/* Avoid calling getaddrinfo() if the name is an IP address */
if (UTI_StringToIP(name, &ip)) {
if (address_family != IPADDR_UNSPEC && ip.family != address_family)
return DNS_Failure;
if (max_addrs >= 1)
ip_addrs[0] = ip;
return DNS_Success;
}
int result;
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_DGRAM;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
result = getaddrinfo(name, NULL, &hints, &res);
@@ -94,34 +64,48 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
#endif
}
for (ai = res, i = 0; i < max_addrs && ai != NULL; ai = ai->ai_next) {
for (ai = res; !result && 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++;
addr->family = IPADDR_INET4;
addr->addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr);
result = 1;
break;
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
case AF_INET6:
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET6)
continue;
/* Don't return an address that would lose a scope ID */
if (((struct sockaddr_in6 *)ai->ai_addr)->sin6_scope_id != 0)
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++;
addr->family = IPADDR_INET6;
memcpy(&addr->addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr, sizeof (addr->addr.in6));
result = 1;
break;
#endif
}
if (result && address_family != IPADDR_UNSPEC && address_family != addr->family)
result = 0;
}
freeaddrinfo(res);
return result ? DNS_Success : DNS_Failure;
#else
struct hostent *host;
host = gethostbyname(name);
return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure;
if (host == NULL) {
if (h_errno == TRY_AGAIN)
return DNS_TryAgain;
} else {
addr->family = IPADDR_INET4;
addr->addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[0]);
return DNS_Success;
}
#ifdef FORCE_DNSRETRY
return DNS_TryAgain;
#else
return DNS_Failure;
#endif
#endif
}
/* ================================================== */
@@ -130,21 +114,54 @@ int
DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
{
char *result = NULL;
#ifdef FEAT_IPV6
struct sockaddr_in6 saddr;
#else
struct sockaddr_in saddr;
#endif
IPSockAddr ip_saddr;
socklen_t slen;
#ifdef HAVE_IPV6
struct sockaddr_in in4;
struct sockaddr_in6 in6;
char hbuf[NI_MAXHOST];
ip_saddr.ip_addr = *ip_addr;
ip_saddr.port = 0;
switch (ip_addr->family) {
case IPADDR_INET4:
memset(&in4, 0, sizeof (in4));
#ifdef SIN6_LEN
in4.sin_len = sizeof (in4);
#endif
in4.sin_family = AF_INET;
in4.sin_addr.s_addr = htonl(ip_addr->addr.in4);
if (!getnameinfo((const struct sockaddr *)&in4, sizeof (in4), hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
break;
case IPADDR_INET6:
memset(&in6, 0, sizeof (in6));
#ifdef SIN6_LEN
in6.sin6_len = sizeof (in6);
#endif
in6.sin6_family = AF_INET6;
memcpy(&in6.sin6_addr.s6_addr, ip_addr->addr.in6, sizeof (in6.sin6_addr.s6_addr));
if (!getnameinfo((const struct sockaddr *)&in6, sizeof (in6), hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
break;
}
#else
struct hostent *host;
uint32_t addr;
slen = SCK_IPSockAddrToSockaddr(&ip_saddr, (struct sockaddr *)&saddr, sizeof (saddr));
if (!getnameinfo((struct sockaddr *)&saddr, slen, hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
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 HAVE_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);

View File

@@ -39,10 +39,7 @@ typedef enum {
/* 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 DNS_Status DNS_Name2IPAddress(const char *name, IPAddr *addr);
extern int DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len);

View File

@@ -31,10 +31,11 @@
#include "nameserv_async.h"
#include "logging.h"
#include "memory.h"
#include "privops.h"
#include "sched.h"
#include "util.h"
#ifdef FEAT_ASYNCDNS
#ifdef USE_PTHREAD_ASYNCDNS
#include <pthread.h>
@@ -43,7 +44,7 @@
struct DNS_Async_Instance {
const char *name;
DNS_Status status;
IPAddr addresses[DNS_MAX_ADDRESSES];
IPAddr addr;
DNS_NameResolveHandler handler;
void *arg;
@@ -51,7 +52,7 @@ struct DNS_Async_Instance {
int pipe[2];
};
static pthread_mutex_t privops_lock = PTHREAD_MUTEX_INITIALIZER;
static int resolving_threads = 0;
/* ================================================== */
@@ -60,9 +61,7 @@ start_resolving(void *anything)
{
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
pthread_mutex_lock(&privops_lock);
inst->status = PRV_Name2IPAddress(inst->name, inst->addresses, DNS_MAX_ADDRESSES);
pthread_mutex_unlock(&privops_lock);
inst->status = DNS_Name2IPAddress(inst->name, &inst->addr);
/* Notify the main thread that the result is ready */
if (write(inst->pipe[1], "", 1) < 0)
@@ -74,24 +73,21 @@ start_resolving(void *anything)
/* ================================================== */
static void
end_resolving(int fd, int event, void *anything)
end_resolving(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");
LOG_FATAL(LOGF_Nameserv, "pthread_join() failed");
}
SCH_RemoveFileHandler(inst->pipe[0]);
resolving_threads--;
SCH_RemoveInputFileHandler(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);
(inst->handler)(inst->status, &inst->addr, inst->arg);
Free(inst);
}
@@ -110,17 +106,17 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
inst->status = DNS_Failure;
if (pipe(inst->pipe)) {
LOG_FATAL("pipe() failed");
LOG_FATAL(LOGF_Nameserv, "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");
LOG_FATAL(LOGF_Nameserv, "pthread_create() failed");
}
SCH_AddFileHandler(inst->pipe[0], SCH_FILE_INPUT, end_resolving, inst);
SCH_AddInputFileHandler(inst->pipe[0], end_resolving, inst);
}
/* ================================================== */
@@ -128,3 +124,21 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
#else
#error
#endif
#else
/* This is a blocking implementation used when nothing else is available */
void
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
{
IPAddr addr;
DNS_Status status;
status = DNS_Name2IPAddress(name, &addr);
(handler)(status, &addr, anything);
}
/* ================================================== */
#endif

View File

@@ -31,10 +31,11 @@
#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);
typedef void (*DNS_NameResolveHandler)(DNS_Status status, IPAddr *ip_addr, void *anything);
/* Request resolving of a name to IP address. The handler will be
called when the result is available. */
called when the result is available, but it may be also called
directly from this function call. */
extern void DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything);
#endif

136
ntp.h
View File

@@ -38,33 +38,7 @@ typedef struct {
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
/* Invalid stratum number */
#define NTP_INVALID_STRATUM 0
/* 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 minimum valid length of an extension field */
#define NTP_MIN_EF_LENGTH 16
/* The maximum assumed length of all extension fields in an NTP packet,
including a MAC (RFC 5905 doesn't specify a limit on length or number of
extension fields in one packet) */
#define NTP_MAX_EXTENSIONS_LENGTH (1024 + NTP_MAX_MAC_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)
#define MAX_NTP_AUTH_DATA_LEN MAX_HASH_LENGTH
/* Type definition for leap bits */
typedef enum {
@@ -95,106 +69,24 @@ typedef struct {
NTP_int64 originate_ts;
NTP_int64 receive_ts;
NTP_int64 transmit_ts;
uint8_t extensions[NTP_MAX_EXTENSIONS_LENGTH];
NTP_int32 auth_keyid;
uint8_t auth_data[MAX_NTP_AUTH_DATA_LEN];
} NTP_Packet;
#define NTP_HEADER_LENGTH (int)offsetof(NTP_Packet, extensions)
/* We have to declare a buffer type to hold a datagram read from the
network. Even though we won't be using them (yet?!), this must be
large enough to hold NTP control messages. */
/* 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))
/* Define the maximum number of bytes that can be read in a single
message. (This is cribbed from ntp.h in the xntpd source code). */
/* 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 */
#define MAX_NTP_MESSAGE_SIZE (468+12+16+4)
/* Non-authentication extension fields and corresponding internal flags */
typedef union {
NTP_Packet ntp_pkt;
uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
} ReceiveBuffer;
#define NTP_EF_EXP_MONO_ROOT 0xF323
#define NTP_EF_EXP_NET_CORRECTION 0xF324
#define NTP_EF_FLAG_EXP_MONO_ROOT 0x1
#define NTP_EF_FLAG_EXP_NET_CORRECTION 0x2
/* Pre-NTPv5 experimental extension field */
typedef struct {
uint32_t magic;
NTP_int32 root_delay;
NTP_int32 root_dispersion;
NTP_int64 mono_receive_ts;
uint32_t mono_epoch;
} NTP_EFExpMonoRoot;
#define NTP_EF_EXP_MONO_ROOT_MAGIC 0xF5BEDD9AU
/* Experimental extension field to provide PTP corrections */
typedef struct {
uint32_t magic;
NTP_int64 correction;
uint32_t reserved[3];
} NTP_EFExpNetCorrection;
#define NTP_EF_EXP_NET_CORRECTION_MAGIC 0x07AC2CEBU
/* Authentication extension fields */
#define NTP_EF_NTS_UNIQUE_IDENTIFIER 0x0104
#define NTP_EF_NTS_COOKIE 0x0204
#define NTP_EF_NTS_COOKIE_PLACEHOLDER 0x0304
#define NTP_EF_NTS_AUTH_AND_EEF 0x0404
/* Enumeration for authentication modes of NTP packets */
typedef enum {
NTP_AUTH_NONE = 0, /* No authentication */
NTP_AUTH_SYMMETRIC, /* NTP MAC or CMAC using a symmetric key
(RFC 1305, RFC 5905, RFC 8573) */
NTP_AUTH_MSSNTP, /* MS-SNTP authenticator field */
NTP_AUTH_MSSNTP_EXT, /* MS-SNTP extended authenticator field */
NTP_AUTH_NTS, /* Network Time Security (RFC 8915) */
} NTP_AuthMode;
/* Structure describing an NTP packet */
typedef struct {
int length;
int version;
NTP_Mode mode;
int ext_fields;
int ext_field_flags;
struct {
NTP_AuthMode mode;
struct {
int start;
int length;
uint32_t key_id;
} mac;
} auth;
} NTP_PacketInfo;
/* Structure used to save NTP measurements. time is the local time at which
the sample is to be considered to have been made and offset is the offset at
the time (positive indicates that the local clock is slow relative to the
source). root_delay/root_dispersion include peer_delay/peer_dispersion. */
typedef struct {
struct timespec time;
double offset;
double peer_delay;
double peer_dispersion;
double root_delay;
double root_dispersion;
} NTP_Sample;
/* Possible sources of timestamps */
typedef enum {
NTP_TS_DAEMON = 0,
NTP_TS_KERNEL,
NTP_TS_HARDWARE
} NTP_Timestamp_Source;
#define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
#endif /* GOT_NTP_H */

View File

@@ -1,386 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019-2020
*
* 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.
*
**********************************************************************
=======================================================================
NTP authentication
*/
#include "config.h"
#include "sysincl.h"
#include "keys.h"
#include "logging.h"
#include "memory.h"
#include "ntp_auth.h"
#include "ntp_signd.h"
#include "nts_ntp.h"
#include "nts_ntp_client.h"
#include "nts_ntp_server.h"
#include "srcparams.h"
#include "util.h"
/* Structure to hold authentication configuration and state */
struct NAU_Instance_Record {
NTP_AuthMode mode; /* Authentication mode of NTP packets */
uint32_t key_id; /* Identifier of a symmetric key */
NNC_Instance nts; /* Client NTS state */
};
/* ================================================== */
static int
generate_symmetric_auth(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info)
{
int auth_len, max_auth_len;
if (info->length + NTP_MIN_MAC_LENGTH > sizeof (*packet)) {
DEBUG_LOG("Packet too long");
return 0;
}
/* Truncate long MACs in NTPv4 packets to allow deterministic parsing
of extension fields (RFC 7822) */
max_auth_len = (info->version == 4 ? NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH) - 4;
max_auth_len = MIN(max_auth_len, sizeof (*packet) - info->length - 4);
auth_len = KEY_GenerateAuth(key_id, packet, info->length,
(unsigned char *)packet + info->length + 4, max_auth_len);
if (auth_len < NTP_MIN_MAC_LENGTH - 4) {
DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
return 0;
}
*(uint32_t *)((unsigned char *)packet + info->length) = htonl(key_id);
info->auth.mac.start = info->length;
info->auth.mac.length = 4 + auth_len;
info->auth.mac.key_id = key_id;
info->length += info->auth.mac.length;
return 1;
}
/* ================================================== */
static int
check_symmetric_auth(NTP_Packet *packet, NTP_PacketInfo *info)
{
int trunc_len;
if (info->auth.mac.length < NTP_MIN_MAC_LENGTH)
return 0;
trunc_len = info->version == 4 && info->auth.mac.length <= NTP_MAX_V4_MAC_LENGTH ?
NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH;
if (!KEY_CheckAuth(info->auth.mac.key_id, packet, info->auth.mac.start,
(unsigned char *)packet + info->auth.mac.start + 4,
info->auth.mac.length - 4, trunc_len - 4))
return 0;
return 1;
}
/* ================================================== */
static NAU_Instance
create_instance(NTP_AuthMode mode)
{
NAU_Instance instance;
instance = MallocNew(struct NAU_Instance_Record);
instance->mode = mode;
instance->key_id = INACTIVE_AUTHKEY;
instance->nts = NULL;
assert(sizeof (instance->key_id) == 4);
return instance;
}
/* ================================================== */
NAU_Instance
NAU_CreateNoneInstance(void)
{
return create_instance(NTP_AUTH_NONE);
}
/* ================================================== */
NAU_Instance
NAU_CreateSymmetricInstance(uint32_t key_id)
{
NAU_Instance instance = create_instance(NTP_AUTH_SYMMETRIC);
instance->key_id = key_id;
if (!KEY_KeyKnown(key_id))
LOG(LOGS_WARN, "Key %"PRIu32" is %s", key_id, "missing");
else if (!KEY_CheckKeyLength(key_id))
LOG(LOGS_WARN, "Key %"PRIu32" is %s", key_id, "too short");
return instance;
}
/* ================================================== */
NAU_Instance
NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name, uint32_t cert_set,
uint16_t ntp_port)
{
NAU_Instance instance = create_instance(NTP_AUTH_NTS);
instance->nts = NNC_CreateInstance(nts_address, name, cert_set, ntp_port);
return instance;
}
/* ================================================== */
void
NAU_DestroyInstance(NAU_Instance instance)
{
if (instance->mode == NTP_AUTH_NTS)
NNC_DestroyInstance(instance->nts);
Free(instance);
}
/* ================================================== */
int
NAU_IsAuthEnabled(NAU_Instance instance)
{
return instance->mode != NTP_AUTH_NONE;
}
/* ================================================== */
int
NAU_GetSuggestedNtpVersion(NAU_Instance instance)
{
/* If the MAC in NTPv4 packets would be truncated, prefer NTPv3 for
compatibility with older chronyd servers */
if (instance->mode == NTP_AUTH_SYMMETRIC &&
KEY_GetAuthLength(instance->key_id) + sizeof (instance->key_id) > NTP_MAX_V4_MAC_LENGTH)
return 3;
return NTP_VERSION;
}
/* ================================================== */
int
NAU_PrepareRequestAuth(NAU_Instance instance)
{
switch (instance->mode) {
case NTP_AUTH_NTS:
if (!NNC_PrepareForAuth(instance->nts))
return 0;
break;
default:
break;
}
return 1;
}
/* ================================================== */
int
NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request, NTP_PacketInfo *info)
{
switch (instance->mode) {
case NTP_AUTH_NONE:
break;
case NTP_AUTH_SYMMETRIC:
if (!generate_symmetric_auth(instance->key_id, request, info))
return 0;
break;
case NTP_AUTH_NTS:
if (!NNC_GenerateRequestAuth(instance->nts, request, info))
return 0;
break;
default:
assert(0);
}
info->auth.mode = instance->mode;
return 1;
}
/* ================================================== */
int
NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info, uint32_t *kod)
{
*kod = 0;
switch (info->auth.mode) {
case NTP_AUTH_NONE:
break;
case NTP_AUTH_SYMMETRIC:
if (!check_symmetric_auth(request, info))
return 0;
break;
case NTP_AUTH_MSSNTP:
/* MS-SNTP requests are not authenticated */
break;
case NTP_AUTH_MSSNTP_EXT:
/* Not supported yet */
return 0;
case NTP_AUTH_NTS:
if (!NNS_CheckRequestAuth(request, info, kod))
return 0;
break;
default:
return 0;
}
return 1;
}
/* ================================================== */
int
NAU_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *request_info,
NTP_Packet *response, NTP_PacketInfo *response_info,
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
uint32_t kod)
{
switch (request_info->auth.mode) {
case NTP_AUTH_NONE:
break;
case NTP_AUTH_SYMMETRIC:
if (!generate_symmetric_auth(request_info->auth.mac.key_id, response, response_info))
return 0;
break;
case NTP_AUTH_MSSNTP:
/* Sign the packet asynchronously by ntp_signd */
if (!NSD_SignAndSendPacket(request_info->auth.mac.key_id, response, response_info,
remote_addr, local_addr))
return 0;
/* Don't send the original packet */
return 0;
case NTP_AUTH_NTS:
if (!NNS_GenerateResponseAuth(request, request_info, response, response_info, kod))
return 0;
break;
default:
DEBUG_LOG("Could not authenticate response auth_mode=%d", (int)request_info->auth.mode);
return 0;
}
response_info->auth.mode = request_info->auth.mode;
return 1;
}
/* ================================================== */
int
NAU_CheckResponseAuth(NAU_Instance instance, NTP_Packet *response, NTP_PacketInfo *info)
{
/* The authentication must match the expected mode */
if (info->auth.mode != instance->mode)
return 0;
switch (info->auth.mode) {
case NTP_AUTH_NONE:
break;
case NTP_AUTH_SYMMETRIC:
/* Check if it is authenticated with the specified key */
if (info->auth.mac.key_id != instance->key_id)
return 0;
/* and that the MAC is valid */
if (!check_symmetric_auth(response, info))
return 0;
break;
case NTP_AUTH_NTS:
if (!NNC_CheckResponseAuth(instance->nts, response, info))
return 0;
break;
default:
return 0;
}
return 1;
}
/* ================================================== */
void
NAU_ChangeAddress(NAU_Instance instance, IPAddr *address)
{
switch (instance->mode) {
case NTP_AUTH_NONE:
case NTP_AUTH_SYMMETRIC:
break;
case NTP_AUTH_NTS:
NNC_ChangeAddress(instance->nts, address);
break;
default:
assert(0);
}
}
/* ================================================== */
void
NAU_DumpData(NAU_Instance instance)
{
switch (instance->mode) {
case NTP_AUTH_NTS:
NNC_DumpData(instance->nts);
break;
default:
break;
}
}
/* ================================================== */
void
NAU_GetReport(NAU_Instance instance, RPT_AuthReport *report)
{
memset(report, 0, sizeof (*report));
report->mode = instance->mode;
report->last_ke_ago = -1;
switch (instance->mode) {
case NTP_AUTH_NONE:
break;
case NTP_AUTH_SYMMETRIC:
report->key_id = instance->key_id;
KEY_GetKeyInfo(instance->key_id, &report->key_type, &report->key_length);
break;
case NTP_AUTH_NTS:
NNC_GetReport(instance->nts, report);
break;
default:
assert(0);
}
}

View File

@@ -1,84 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019
*
* 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 NTP authentication
*/
#ifndef GOT_NTP_AUTH_H
#define GOT_NTP_AUTH_H
#include "addressing.h"
#include "ntp.h"
#include "reports.h"
typedef struct NAU_Instance_Record *NAU_Instance;
/* Create an authenticator instance in a specific mode */
extern NAU_Instance NAU_CreateNoneInstance(void);
extern NAU_Instance NAU_CreateSymmetricInstance(uint32_t key_id);
extern NAU_Instance NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name,
uint32_t cert_set, uint16_t ntp_port);
/* Destroy an instance */
extern void NAU_DestroyInstance(NAU_Instance instance);
/* Check if an instance is not in the None mode */
extern int NAU_IsAuthEnabled(NAU_Instance instance);
/* Get NTP version recommended for better compatibility */
extern int NAU_GetSuggestedNtpVersion(NAU_Instance instance);
/* Perform operations necessary for NAU_GenerateRequestAuth() */
extern int NAU_PrepareRequestAuth(NAU_Instance instance);
/* Extend a request with data required by the authentication mode */
extern int NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request,
NTP_PacketInfo *info);
/* Verify that a request is authentic. If it is not authentic and a non-zero
kod code is returned, a KoD response should be sent back. */
extern int NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info, uint32_t *kod);
/* Extend a response with data required by the authentication mode. This
function can be called only if the previous call of NAU_CheckRequestAuth()
was on the same request. */
extern int NAU_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *request_info,
NTP_Packet *response, NTP_PacketInfo *response_info,
NTP_Remote_Address *remote_addr,
NTP_Local_Address *local_addr,
uint32_t kod);
/* Verify that a response is authentic */
extern int NAU_CheckResponseAuth(NAU_Instance instance, NTP_Packet *response,
NTP_PacketInfo *info);
/* Change an authentication-specific address (e.g. after replacing a source) */
extern void NAU_ChangeAddress(NAU_Instance instance, IPAddr *address);
/* Save authentication-specific data to speed up the next start */
extern void NAU_DumpData(NAU_Instance instance);
/* Provide a report about the current authentication state */
extern void NAU_GetReport(NAU_Instance instance, RPT_AuthReport *report);
#endif

3215
ntp_core.c

File diff suppressed because it is too large Load Diff

View File

@@ -38,14 +38,6 @@ typedef enum {
NTP_SERVER, NTP_PEER
} NTP_Source_Type;
typedef struct {
struct timespec ts;
double err;
NTP_Timestamp_Source source;
double rx_duration;
double net_correction;
} 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;
@@ -55,8 +47,7 @@ extern void NCR_Initialise(void);
extern void NCR_Finalise(void);
/* Get a new instance for a server or peer */
extern NCR_Instance NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
SourceParameters *params, const char *name);
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);
@@ -67,39 +58,23 @@ 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,
int ntp_only);
/* 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);
extern void NCR_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, int sock_fd, 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);
extern void NCR_ProcessUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);
/* Slew receive and transmit times in instance records */
extern void NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double doffset);
extern void NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset);
/* Take a particular source online (i.e. start sampling it) or offline
(i.e. stop sampling it) */
extern void NCR_SetConnectivity(NCR_Instance inst, SRC_Connectivity connectivity);
/* 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);
@@ -113,15 +88,11 @@ extern void NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_d
extern void NCR_ModifyMinstratum(NCR_Instance inst, int new_min_stratum);
extern void NCR_ModifyOffset(NCR_Instance inst, double new_offset);
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_GetAuthReport(NCR_Instance inst, RPT_AuthReport *report);
extern void NCR_GetNTPReport(NCR_Instance inst, RPT_NTPReport *report);
extern void NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timeval *now);
extern int NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all);
extern int NCR_CheckAccessRestriction(IPAddr *ip_addr);
@@ -131,12 +102,6 @@ extern void NCR_IncrementActivityCounters(NCR_Instance inst, int *online, int *o
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_DumpAuthData(NCR_Instance inst);
extern void NCR_AddBroadcastDestination(NTP_Remote_Address *addr, int interval);
#endif /* GOT_NTP_CORE_H */

192
ntp_ext.c
View File

@@ -1,192 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019-2020
*
* 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 adding and parsing NTPv4 extension fields
*/
#include "config.h"
#include "sysincl.h"
#include "ntp_ext.h"
struct ExtFieldHeader {
uint16_t type;
uint16_t length;
};
/* ================================================== */
static int
format_field(unsigned char *buffer, int buffer_length, int start,
int type, int body_length, int *length, void **body)
{
struct ExtFieldHeader *header;
if (buffer_length < 0 || start < 0 || buffer_length <= start ||
buffer_length - start < sizeof (*header) || start % 4 != 0)
return 0;
header = (struct ExtFieldHeader *)(buffer + start);
if (body_length < 0 || sizeof (*header) + body_length > 0xffff ||
start + sizeof (*header) + body_length > buffer_length || body_length % 4 != 0)
return 0;
header->type = htons(type);
header->length = htons(sizeof (*header) + body_length);
*length = sizeof (*header) + body_length;
*body = header + 1;
return 1;
}
/* ================================================== */
int
NEF_SetField(unsigned char *buffer, int buffer_length, int start,
int type, void *body, int body_length, int *length)
{
void *ef_body;
if (!format_field(buffer, buffer_length, start, type, body_length, length, &ef_body))
return 0;
memcpy(ef_body, body, body_length);
return 1;
}
/* ================================================== */
int
NEF_AddBlankField(NTP_Packet *packet, NTP_PacketInfo *info, int type, int body_length, void **body)
{
int ef_length, length = info->length;
if (length < NTP_HEADER_LENGTH || length >= sizeof (*packet) || length % 4 != 0)
return 0;
/* Only NTPv4 packets can have extension fields */
if (info->version != 4)
return 0;
if (!format_field((unsigned char *)packet, sizeof (*packet), length,
type, body_length, &ef_length, body))
return 0;
if (ef_length < NTP_MIN_EF_LENGTH)
return 0;
info->length += ef_length;
info->ext_fields++;
return 1;
}
/* ================================================== */
int
NEF_AddField(NTP_Packet *packet, NTP_PacketInfo *info,
int type, void *body, int body_length)
{
void *ef_body;
if (!NEF_AddBlankField(packet, info, type, body_length, &ef_body))
return 0;
memcpy(ef_body, body, body_length);
return 1;
}
/* ================================================== */
int
NEF_ParseSingleField(unsigned char *buffer, int buffer_length, int start,
int *length, int *type, void **body, int *body_length)
{
struct ExtFieldHeader *header;
int ef_length;
if (buffer_length < 0 || start < 0 || buffer_length <= start ||
buffer_length - start < sizeof (*header))
return 0;
header = (struct ExtFieldHeader *)(buffer + start);
assert(sizeof (*header) == 4);
ef_length = ntohs(header->length);
if (ef_length < (int)(sizeof (*header)) || start + ef_length > buffer_length ||
ef_length % 4 != 0)
return 0;
if (length)
*length = ef_length;
if (type)
*type = ntohs(header->type);
if (body)
*body = header + 1;
if (body_length)
*body_length = ef_length - sizeof (*header);
return 1;
}
/* ================================================== */
int
NEF_ParseField(NTP_Packet *packet, int packet_length, int start,
int *length, int *type, void **body, int *body_length)
{
int ef_length;
if (packet_length <= NTP_HEADER_LENGTH || packet_length > sizeof (*packet) ||
packet_length <= start || packet_length % 4 != 0 ||
start < NTP_HEADER_LENGTH || start % 4 != 0)
return 0;
/* Only NTPv4 packets have extension fields */
if (NTP_LVM_TO_VERSION(packet->lvm) != 4)
return 0;
/* Check if the remaining data is a MAC. RFC 7822 specifies the maximum
length of a MAC in NTPv4 packets in order to enable deterministic
parsing. */
if (packet_length - start <= NTP_MAX_V4_MAC_LENGTH)
return 0;
if (!NEF_ParseSingleField((unsigned char *)packet, packet_length, start,
&ef_length, type, body, body_length))
return 0;
if (ef_length < NTP_MIN_EF_LENGTH)
return 0;
if (length)
*length = ef_length;
return 1;
}

View File

@@ -1,43 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019
*
* 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 NTP extension fields
*/
#ifndef GOT_NTP_EXT_H
#define GOT_NTP_EXT_H
#include "ntp.h"
extern int NEF_SetField(unsigned char *buffer, int buffer_length, int start,
int type, void *body, int body_length, int *length);
extern int NEF_AddBlankField(NTP_Packet *packet, NTP_PacketInfo *info, int type,
int body_length, void **body);
extern int NEF_AddField(NTP_Packet *packet, NTP_PacketInfo *info,
int type, void *body, int body_length);
extern int NEF_ParseSingleField(unsigned char *buffer, int buffer_length, int start,
int *length, int *type, void **body, int *body_length);
extern int NEF_ParseField(NTP_Packet *packet, int packet_length, int start,
int *length, int *type, void **body, int *body_length);
#endif

901
ntp_io.c

File diff suppressed because it is too large Load Diff

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