mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-04 01:25:07 -05:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aabb564320 | ||
|
|
df46e5ca5d | ||
|
|
370ba5e8fc | ||
|
|
463093803d | ||
|
|
c4bedce1f4 | ||
|
|
79eacdb7e6 | ||
|
|
cf19042ecb | ||
|
|
d856bd34c4 |
35
.gitignore
vendored
35
.gitignore
vendored
@@ -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
|
||||
|
||||
143
Makefile.in
143
Makefile.in
@@ -21,60 +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@
|
||||
|
||||
EXTRA_OBJS = @EXTRA_OBJS@
|
||||
|
||||
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o \
|
||||
reference.o regress.o rtc.o samplefilt.o sched.o 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)
|
||||
|
||||
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
|
||||
@@ -84,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
|
||||
@@ -95,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 $<
|
||||
@@ -109,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
|
||||
@@ -134,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
|
||||
|
||||
372
NEWS
372
NEWS
@@ -1,378 +1,10 @@
|
||||
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
|
||||
=====================
|
||||
|
||||
|
||||
299
README
299
README
@@ -3,70 +3,111 @@ 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 continuosly, 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
|
||||
Solaris. 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.tuxfamily.org/
|
||||
http://chrony.tuxfamily.org/
|
||||
|
||||
Where are new versions announced?
|
||||
=================================
|
||||
|
||||
There is a low volume mailing list where new versions and other
|
||||
important news relating to chrony are announced. You can join this list
|
||||
important news relating to chrony is announced. You can join this list
|
||||
by sending mail with the subject "subscribe" to
|
||||
|
||||
chrony-announce-request@chrony.tuxfamily.org
|
||||
|
||||
How can I get support for chrony?
|
||||
=================================
|
||||
These messages will be copied to chrony-users (see below).
|
||||
|
||||
There are two other mailing lists relating to chrony. chrony-users is a
|
||||
discussion list for users, e.g. for questions about chrony configuration
|
||||
and bug reports. chrony-dev is a more technical list for developers,
|
||||
e.g. for submitting patches and discussing how new features should be
|
||||
implemented. To subscribe to either of these lists, send a message with
|
||||
the subject "subscribe" to
|
||||
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
|
||||
@@ -74,82 +115,136 @@ chrony-dev-request@chrony.tuxfamily.org
|
||||
|
||||
as applicable.
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
chrony is distributed under the GNU General Public License version 2.
|
||||
|
||||
Authors
|
||||
=======
|
||||
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>
|
||||
Stephan I. Boettcher <stephan@nevis1.columbia.edu>
|
||||
David Bohman <debohman@gmail.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>
|
||||
Christian Ehrhardt <christian.ehrhardt@canonical.com>
|
||||
Paul Elliott <pelliott@io.com>
|
||||
Robert Fairley <rfairley@redhat.com>
|
||||
Stefan R. Filipek <srfilipek@gmail.com>
|
||||
Mike Fleetwood <mike@rockover.demon.co.uk>
|
||||
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>
|
||||
Jachym Holecek <jakym@volny.cz>
|
||||
Håkan Johansson <f96hajo@chalmers.se>
|
||||
Jim Knoble <jmknoble@pobox.com>
|
||||
Antti Jrvinen <costello@iki.fi>
|
||||
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>
|
||||
Frank Otto <sandwichmacher@web.de>
|
||||
Denny Page <dennypage@me.com>
|
||||
Chris Perl <cperl@janestreet.com>
|
||||
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
|
||||
Andreas Piesk <apiesk@virbus.de>
|
||||
Andreas Steinmetz <ast@domdv.de>
|
||||
NAKAMURA Takumi <takumi@ps.sakura.ne.jp>
|
||||
Timo Teras <timo.teras@iki.fi>
|
||||
Bill Unruh <unruh@physics.ubc.ca>
|
||||
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>
|
||||
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.
|
||||
|
||||
13
addressing.h
13
addressing.h
@@ -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;
|
||||
|
||||
|
||||
146
addrfilt.c
146
addrfilt.c
@@ -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 */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
130
array.c
130
array.c
@@ -1,130 +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_SetSize(ARR_Instance array, unsigned int size)
|
||||
{
|
||||
realloc_array(array, size);
|
||||
array->used = size;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ARR_GetSize(ARR_Instance array)
|
||||
{
|
||||
return array->used;
|
||||
}
|
||||
56
array.h
56
array.h
@@ -1,56 +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);
|
||||
|
||||
/* 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
159
broadcast.c
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,35 +2,36 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) John G. Hasler 2009
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2018
|
||||
*
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
The header file for shared Posix functionality
|
||||
Deal with broadcast server functions.
|
||||
*/
|
||||
|
||||
#ifndef GOT_SYS_POSIX_H
|
||||
#define GOT_SYS_POSIX_H
|
||||
#ifndef GOT_BROADCAST_H
|
||||
#define GOT_BROADCAST_H
|
||||
|
||||
extern void SYS_Posix_MemLockAll(void);
|
||||
#include "addressing.h"
|
||||
|
||||
extern void SYS_Posix_SetScheduler(int priority);
|
||||
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_SYS_POSIX_H */
|
||||
376
candm.h
376
candm.h
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
#include "addressing.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* This is the default port to use for CANDM, if no alternative is
|
||||
defined */
|
||||
@@ -87,35 +88,18 @@
|
||||
#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 N_REQUEST_TYPES 71
|
||||
#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
|
||||
@@ -131,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;
|
||||
@@ -208,26 +188,18 @@ typedef struct {
|
||||
} REQ_Modify_Maxupdateskew;
|
||||
|
||||
typedef struct {
|
||||
int32_t limit;
|
||||
Float threshold;
|
||||
int32_t EOR;
|
||||
} REQ_Modify_Makestep;
|
||||
|
||||
typedef struct {
|
||||
Timespec ts;
|
||||
Timeval ts;
|
||||
int32_t EOR;
|
||||
} 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;
|
||||
int32_t EOR;
|
||||
} REQ_Local;
|
||||
|
||||
@@ -236,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;
|
||||
@@ -252,47 +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
|
||||
|
||||
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 reserved[3];
|
||||
int32_t EOR;
|
||||
} REQ_NTP_Source;
|
||||
|
||||
@@ -301,6 +257,10 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Del_Source;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_WriteRtc;
|
||||
|
||||
typedef struct {
|
||||
Float dfreq;
|
||||
int32_t EOR;
|
||||
@@ -312,61 +272,68 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Doffset;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Tracking;
|
||||
|
||||
typedef struct {
|
||||
uint32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_Sourcestats;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_RTCReport;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_TrimRTC;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_CycleLogs;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip;
|
||||
uint32_t bits_specd;
|
||||
} REQ_SubnetsAccessed_Subnet;
|
||||
|
||||
/* This is based on the response size rather than the
|
||||
request size */
|
||||
#define MAX_CLIENT_ACCESSES 8
|
||||
|
||||
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;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define PKT_TYPE_CMD_REQUEST 1
|
||||
@@ -395,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
|
||||
(using new request/reply types) and manual timestamp, added new fields and
|
||||
flags to NTP source request and report, made length of manual list constant,
|
||||
added new commands: authdata, ntpdata, onoffline, refresh, reset,
|
||||
selectdata, serverstats, shutdown, sourcename
|
||||
changed maximum number of samples in manual list to 16
|
||||
*/
|
||||
|
||||
#define PROTO_VERSION_NUMBER 6
|
||||
@@ -420,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
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -435,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;
|
||||
@@ -452,33 +407,43 @@ 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;
|
||||
} 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;
|
||||
|
||||
/* ================================================== */
|
||||
@@ -503,18 +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 N_REPLY_TYPES 24
|
||||
#define N_REPLY_TYPES 13
|
||||
|
||||
/* Status codes */
|
||||
#define STT_SUCCESS 0
|
||||
@@ -538,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;
|
||||
@@ -553,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;
|
||||
@@ -580,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;
|
||||
@@ -608,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;
|
||||
@@ -618,7 +574,7 @@ typedef struct {
|
||||
} RPY_Rtc;
|
||||
|
||||
typedef struct {
|
||||
Float offset;
|
||||
uint32_t centiseconds;
|
||||
Float dfreq_ppm;
|
||||
Float new_afreq_ppm;
|
||||
int32_t EOR;
|
||||
@@ -626,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;
|
||||
|
||||
@@ -649,22 +605,10 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} RPY_ClientAccessesByIndex;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ntp_hits;
|
||||
uint32_t nke_hits;
|
||||
uint32_t cmd_hits;
|
||||
uint32_t ntp_drops;
|
||||
uint32_t nke_drops;
|
||||
uint32_t cmd_drops;
|
||||
uint32_t log_drops;
|
||||
uint32_t ntp_auth_hits;
|
||||
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;
|
||||
@@ -685,96 +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 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;
|
||||
@@ -787,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;
|
||||
@@ -799,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
71
chrony.1
Normal 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
55
chrony.conf.5.in
Normal 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
5172
chrony.texi.in
Normal file
File diff suppressed because it is too large
Load Diff
73
chrony_timex.h
Normal file
73
chrony_timex.h
Normal 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
75
chronyc.1.in
Normal 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
154
chronyd.8.in
Normal 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.
|
||||
|
||||
932
clientlog.c
932
clientlog.c
File diff suppressed because it is too large
Load Diff
60
clientlog.h
60
clientlog.h
@@ -31,27 +31,55 @@
|
||||
#include "sysincl.h"
|
||||
#include "reports.h"
|
||||
|
||||
typedef enum {
|
||||
CLG_NTP = 0,
|
||||
CLG_NTSKE,
|
||||
CLG_CMDMON,
|
||||
} CLG_Service;
|
||||
/* 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 int CLG_LimitServiceRate(CLG_Service service, int index);
|
||||
extern void CLG_LogAuthNtpRequest(void);
|
||||
extern void CLG_GetNtpTimestamps(int index, NTP_int64 **rx_ts, NTP_int64 **tx_ts);
|
||||
extern int CLG_GetNtpMinPoll(void);
|
||||
extern void CLG_LogNTPClientAccess(IPAddr *client, time_t now);
|
||||
extern void CLG_LogNTPPeerAccess(IPAddr *client, time_t now);
|
||||
|
||||
/* 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
48
cmac.h
@@ -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
|
||||
|
||||
117
cmac_nettle.c
117
cmac_nettle.c
@@ -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);
|
||||
}
|
||||
3
cmdmon.h
3
cmdmon.h
@@ -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);
|
||||
|
||||
|
||||
286
cmdparse.c
286
cmdparse.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2013-2014, 2016
|
||||
* 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,178 +34,164 @@
|
||||
#include "cmdparse.h"
|
||||
#include "memory.h"
|
||||
#include "nameserv.h"
|
||||
#include "ntp.h"
|
||||
#include "util.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CPS_Status
|
||||
CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
{
|
||||
char *hostname, *cmd;
|
||||
int n;
|
||||
int ok, n, done;
|
||||
CPS_Status result;
|
||||
|
||||
src->port = SRC_DEFAULT_PORT;
|
||||
src->params.minpoll = SRC_DEFAULT_MINPOLL;
|
||||
src->params.maxpoll = SRC_DEFAULT_MAXPOLL;
|
||||
src->params.connectivity = SRC_ONLINE;
|
||||
src->params.auto_offline = 0;
|
||||
src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
|
||||
src->params.burst = 0;
|
||||
src->params.iburst = 0;
|
||||
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
|
||||
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
|
||||
src->params.version = 0;
|
||||
src->params.max_sources = SRC_DEFAULT_MAXSOURCES;
|
||||
src->params.min_samples = SRC_DEFAULT_MINSAMPLES;
|
||||
src->params.max_samples = SRC_DEFAULT_MAXSAMPLES;
|
||||
src->params.filter_length = 0;
|
||||
src->params.interleaved = 0;
|
||||
src->params.sel_options = 0;
|
||||
src->params.nts = 0;
|
||||
src->params.nts_port = SRC_DEFAULT_NTSPORT;
|
||||
src->params.authkey = INACTIVE_AUTHKEY;
|
||||
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
|
||||
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
|
||||
src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
|
||||
src->params.min_delay = 0.0;
|
||||
src->params.asymmetry = SRC_DEFAULT_ASYMMETRY;
|
||||
src->params.offset = 0.0;
|
||||
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 0;
|
||||
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, "iburst")) {
|
||||
src->params.iburst = 1;
|
||||
} else if (!strcasecmp(cmd, "offline")) {
|
||||
src->params.connectivity = SRC_OFFLINE;
|
||||
} else if (!strcasecmp(cmd, "noselect")) {
|
||||
src->params.sel_options |= SRC_SELECT_NOSELECT;
|
||||
} else if (!strcasecmp(cmd, "prefer")) {
|
||||
src->params.sel_options |= SRC_SELECT_PREFER;
|
||||
} else if (!strcasecmp(cmd, "require")) {
|
||||
src->params.sel_options |= SRC_SELECT_REQUIRE;
|
||||
} else if (!strcasecmp(cmd, "trust")) {
|
||||
src->params.sel_options |= SRC_SELECT_TRUST;
|
||||
} else if (!strcasecmp(cmd, "key")) {
|
||||
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
|
||||
src->params.authkey == INACTIVE_AUTHKEY)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "asymmetry")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.asymmetry, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "filter")) {
|
||||
if (sscanf(line, "%d%n", &src->params.filter_length, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "maxdelay")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "maxdelayratio")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "maxpoll")) {
|
||||
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "maxsamples")) {
|
||||
if (sscanf(line, "%d%n", &src->params.max_samples, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "maxsources")) {
|
||||
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "mindelay")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.min_delay, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "minpoll")) {
|
||||
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "minsamples")) {
|
||||
if (sscanf(line, "%d%n", &src->params.min_samples, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "minstratum")) {
|
||||
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "nts")) {
|
||||
src->params.nts = 1;
|
||||
} else if (!strcasecmp(cmd, "ntsport")) {
|
||||
if (sscanf(line, "%d%n", &src->params.nts_port, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "offset")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.offset, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "port")) {
|
||||
if (sscanf(line, "%d%n", &src->port, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "polltarget")) {
|
||||
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "presend")) {
|
||||
if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "version")) {
|
||||
if (sscanf(line, "%d%n", &src->params.version, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "xleave")) {
|
||||
src->params.interleaved = 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance)
|
||||
{
|
||||
int n;
|
||||
char *cmd;
|
||||
|
||||
*stratum = 10;
|
||||
*distance = 1.0;
|
||||
*orphan = 0;
|
||||
|
||||
while (*line) {
|
||||
cmd = line;
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
if (!strcasecmp(cmd, "stratum")) {
|
||||
if (sscanf(line, "%d%n", stratum, &n) != 1 ||
|
||||
*stratum >= NTP_MAX_STRATUM || *stratum <= 0)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "orphan")) {
|
||||
*orphan = 1;
|
||||
n = 0;
|
||||
} else if (!strcasecmp(cmd, "distance")) {
|
||||
if (sscanf(line, "%lf%n", distance, &n) != 1)
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
line += n;
|
||||
if (ok) {
|
||||
src->name = strdup(hostname);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -268,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;
|
||||
|
||||
@@ -281,14 +267,14 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
25
cmdparse.h
25
cmdparse.h
@@ -30,18 +30,31 @@
|
||||
#include "srcparams.h"
|
||||
#include "addressing.h"
|
||||
|
||||
typedef enum {
|
||||
CPS_Success,
|
||||
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 port;
|
||||
unsigned short port;
|
||||
SourceParameters params;
|
||||
} CPS_NTP_Source;
|
||||
|
||||
/* Parse a command to add an NTP server or peer */
|
||||
extern int CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
|
||||
extern CPS_Status CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
|
||||
|
||||
/* Parse a command to enable local reference */
|
||||
extern int CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance);
|
||||
|
||||
/* Remove extra white-space and comments */
|
||||
extern void CPS_NormalizeLine(char *line);
|
||||
|
||||
@@ -49,6 +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);
|
||||
extern int CPS_ParseKey(char *line, unsigned long *id, const char **hash, char **key);
|
||||
|
||||
#endif /* GOT_CMDPARSE_H */
|
||||
|
||||
74
conf.h
74
conf.h
@@ -29,35 +29,26 @@
|
||||
#define GOT_CONF_H
|
||||
|
||||
#include "addressing.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_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(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_GetLogMeasurements(void);
|
||||
extern int CNF_GetLogStatistics(void);
|
||||
extern int CNF_GetLogTracking(void);
|
||||
extern int CNF_GetLogRtc(void);
|
||||
@@ -65,13 +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 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);
|
||||
@@ -79,89 +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);
|
||||
|
||||
/* 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 double CNF_GetReselectDistance(void);
|
||||
extern double CNF_GetStratumWeight(void);
|
||||
extern double CNF_GetCombineLimit(void);
|
||||
|
||||
extern int CNF_AllowLocalReference(int *stratum, int *orphan, double *distance);
|
||||
extern 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);
|
||||
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_ALL,
|
||||
} CNF_HwTs_RxFilter;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int minpoll;
|
||||
int min_samples;
|
||||
int max_samples;
|
||||
int nocrossts;
|
||||
CNF_HwTs_RxFilter rxfilter;
|
||||
double precision;
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
} CNF_HwTsInterface;
|
||||
|
||||
extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
|
||||
|
||||
extern char *CNF_GetNtsDumpDir(void);
|
||||
extern char *CNF_GetNtsNtpServer(void);
|
||||
extern char *CNF_GetNtsServerCertFile(void);
|
||||
extern char *CNF_GetNtsServerKeyFile(void);
|
||||
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 char *CNF_GetNtsTrustedCertFile(void);
|
||||
extern int CNF_GetNoSystemCert(void);
|
||||
extern int CNF_GetNoCertTimeCheck(void);
|
||||
|
||||
#endif /* GOT_CONF_H */
|
||||
|
||||
339
contrib/DNSchrony/COPYING
Normal file
339
contrib/DNSchrony/COPYING
Normal 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
583
contrib/DNSchrony/DNSchrony.pl
Executable 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
21
contrib/DNSchrony/DNSchronyADD
Executable 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"
|
||||
7
contrib/DNSchrony/DNSchronyDELETE
Executable file
7
contrib/DNSchrony/DNSchronyDELETE
Executable 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
|
||||
7
contrib/DNSchrony/DNSchronyUPDATE
Executable file
7
contrib/DNSchrony/DNSchronyUPDATE
Executable 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
166
contrib/DNSchrony/README
Normal 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
|
||||
22
contrib/DNSchrony/ip-up.local
Normal file
22
contrib/DNSchrony/ip-up.local
Normal 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
|
||||
@@ -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.tuxfamily.chronyc.plist
|
||||
-rw-r--r-- 1 yourname staff 511 19 Jun 18:30 org.tuxfamily.chronyd.plist
|
||||
|
||||
If you have used chrony support directories other than those suggested, you
|
||||
will need to edit each file and make the appropriate changes.
|
||||
|
||||
|
||||
Installing the support files
|
||||
----------------------------
|
||||
|
||||
1. chronylogrotate.sh
|
||||
This is a simple shell script that deletes old log files. Unfortunately because
|
||||
of the need to run chronyc, the standard macOS logrotation does not work with
|
||||
chrony logs.
|
||||
|
||||
This script runs on a daily basis under control of launchd and should be
|
||||
installed in the /usr/local/bin directory
|
||||
|
||||
sudo cp chronylogrotate.sh /usr/local/bin
|
||||
sudo chmod +x /usr/local/bin/chronylogrotate.sh
|
||||
sudo chown root:wheel /usr/local/bin/chronylogrotate.sh
|
||||
|
||||
|
||||
2. org.tuxfamily.chronyc.plist
|
||||
This file is the launchd plist that runs logrotation each day. You may
|
||||
wish to edit this file to change the time of day at which the rotation
|
||||
will run, currently 04:05 am
|
||||
|
||||
sudo cp org.tuxfamily.chronyc.plist /Library/LaunchDaemons
|
||||
sudo chown root:wheel /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
|
||||
sudo chmod 0644 /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
|
||||
sudo launchctl load -w /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
|
||||
|
||||
|
||||
3. org.tuxfamily.chronyd.plist
|
||||
This file is the launchd plist that runs chronyd when the Macintosh starts.
|
||||
|
||||
sudo cp org.tuxfamily.chronyd.plist /Library/LaunchDaemons
|
||||
sudo chown root:wheel /Library/LaunchDaemons/org.tuxfamily.chronyd.plist
|
||||
sudo chmod 0644 /Library/LaunchDaemons/org.tuxfamily.chronyd.plist
|
||||
sudo launchctl load -w /Library/LaunchDaemons/org.tuxfamily.chronyd.plist
|
||||
@@ -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 $?
|
||||
@@ -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.tuxfamily.logrotate</string>
|
||||
<key>KeepAlive</key>
|
||||
<false/>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/bin/sh</string>
|
||||
<string>/usr/local/bin/chronylogrotate.sh</string>
|
||||
</array>
|
||||
<key>StartCalendarInterval</key>
|
||||
<dict>
|
||||
<key>Minute</key>
|
||||
<integer>5</integer>
|
||||
<key>Hour</key>
|
||||
<integer>4</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -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.tuxfamily.chronyd</string>
|
||||
<key>Program</key>
|
||||
<string>/usr/local/sbin/chronyd</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>chronyd</string>
|
||||
<string>-n</string>
|
||||
<string>-f</string>
|
||||
<string>/private/etc/chrony.d/chrony.conf</string>
|
||||
</array>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,76 +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_HWCLOCK_FILE = @DEFAULT_HWCLOCK_FILE@
|
||||
DEFAULT_PID_FILE = @DEFAULT_PID_FILE@
|
||||
DEFAULT_RTC_DEVICE = @DEFAULT_RTC_DEVICE@
|
||||
|
||||
SED_COMMANDS = "s%\@SYSCONFDIR\@%$(SYSCONFDIR)%g;\
|
||||
s%\@BINDIR\@%$(BINDIR)%g;\
|
||||
s%\@SBINDIR\@%$(SBINDIR)%g;\
|
||||
s%\@CHRONY_VERSION\@%$(CHRONY_VERSION)%g;\
|
||||
s%\@DEFAULT_HWCLOCK_FILE\@%$(DEFAULT_HWCLOCK_FILE)%g;\
|
||||
s%\@DEFAULT_PID_FILE\@%$(DEFAULT_PID_FILE)%g;\
|
||||
s%\@DEFAULT_RTC_DEVICE\@%$(DEFAULT_RTC_DEVICE)%g;\
|
||||
s%\@DEFAULT_USER\@%$(DEFAULT_USER)%g;\
|
||||
s%\@CHRONYRUNDIR\@%$(CHRONYRUNDIR)%g;\
|
||||
s%\@CHRONYVARDIR\@%$(CHRONYVARDIR)%g;"
|
||||
|
||||
man: $(MAN_FILES) $(MAN_IN_FILES)
|
||||
html: $(HTML_FILES)
|
||||
txt: $(TXT_FILES)
|
||||
docs: man html
|
||||
|
||||
%.html: %.adoc
|
||||
$(ADOC) $(ADOC_FLAGS) -b html -o - $< | $(SED) -e $(SED_COMMANDS) > $@
|
||||
|
||||
%.man.in: %.adoc
|
||||
$(ADOC) $(ADOC_FLAGS) -b manpage -o $@ $<
|
||||
|
||||
%.man: %.man.in
|
||||
$(SED) -e $(SED_COMMANDS) < $< > $@
|
||||
|
||||
%.txt: %.html
|
||||
$(HTML_TO_TXT) < $< > $@
|
||||
|
||||
install: $(MAN_FILES)
|
||||
[ -d $(DESTDIR)$(MANDIR)/man1 ] || mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||
[ -d $(DESTDIR)$(MANDIR)/man5 ] || mkdir -p $(DESTDIR)$(MANDIR)/man5
|
||||
[ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8
|
||||
cp chronyc.man $(DESTDIR)$(MANDIR)/man1/chronyc.1
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/chronyc.1
|
||||
cp chronyd.man $(DESTDIR)$(MANDIR)/man8/chronyd.8
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man8/chronyd.8
|
||||
cp chrony.conf.man $(DESTDIR)$(MANDIR)/man5/chrony.conf.5
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man5/chrony.conf.5
|
||||
|
||||
install-docs: $(HTML_FILES)
|
||||
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
|
||||
for f in $(HTML_FILES); do \
|
||||
cp $$f $(DESTDIR)$(DOCDIR); \
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/$$f; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -f $(MAN_FILES) $(TXT_FILES) $(HTML_FILES)
|
||||
rm -f $(MAN_IN_FILES)
|
||||
|
||||
distclean:
|
||||
rm -f $(MAN_FILES) $(TXT_FILES) $(HTML_FILES)
|
||||
rm -f Makefile
|
||||
2854
doc/chrony.conf.adoc
2854
doc/chrony.conf.adoc
File diff suppressed because it is too large
Load Diff
1466
doc/chronyc.adoc
1466
doc/chronyc.adoc
File diff suppressed because it is too large
Load Diff
211
doc/chronyd.adoc
211
doc/chronyd.adoc
@@ -1,211 +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:
|
||||
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 it allows *chronyd* to be
|
||||
started without root privileges.
|
||||
|
||||
*-r*::
|
||||
This option will try to reload and then delete files containing sample
|
||||
histories for each of the servers and reference clocks being used. 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,
|
||||
Solaris, and macOS 10.13 or later).
|
||||
|
||||
*-R*::
|
||||
When this option is used, the <<chrony.conf.adoc#initstepslew,*initstepslew*>>
|
||||
directive and the <<chrony.conf.adoc#makestep,*makestep*>> directive used with
|
||||
a positive limit will be ignored. This option is useful when restarting
|
||||
*chronyd* and can be used in conjunction with the *-r* option.
|
||||
|
||||
*-s*::
|
||||
This option will set the system clock from the computer's real-time clock (RTC)
|
||||
or to the last modification time of the file specified by the
|
||||
<<chrony.conf.adoc#driftfile,*driftfile*>> directive. Real-time clocks are
|
||||
supported only on Linux.
|
||||
+
|
||||
If used in conjunction with the *-r* flag, *chronyd* will attempt to preserve
|
||||
the old samples after setting the system clock from the RTC. This can be used
|
||||
to allow *chronyd* to perform long term averaging of the gain or loss rate
|
||||
across system reboots, and is useful for systems with intermittent access to
|
||||
network that are shut down when not in use. For this to work well, it relies
|
||||
on *chronyd* having been able to determine accurate statistics for the
|
||||
difference between the RTC and system clock last time the computer was on.
|
||||
+
|
||||
If the last modification time of the drift file is later than both the current
|
||||
time and the RTC time, the system time will be set to it to restore the time
|
||||
when *chronyd* was previously stopped. This is useful on computers that have no
|
||||
RTC or the RTC is broken (e.g. it has no battery).
|
||||
|
||||
*-t* _timeout_::
|
||||
This option sets a timeout (in seconds) after which *chronyd* will exit. If the
|
||||
clock is not synchronised, it will exit with a non-zero status. This is useful
|
||||
with the *-q* or *-Q* option to shorten the maximum time waiting for
|
||||
measurements, or with the *-r* option to limit the time when *chronyd* is
|
||||
running, but still allow it to adjust the frequency of the system clock.
|
||||
|
||||
*-u* _user_::
|
||||
This option sets the name of the system user to which *chronyd* will switch
|
||||
after start in order to drop root privileges. It overrides the
|
||||
<<chrony.conf.adoc#user,*user*>> directive. 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 Solaris *chronyd* forks into two processes.
|
||||
The child process retains root privileges, but can only perform a very limited
|
||||
range of privileged system calls on behalf of the parent.
|
||||
|
||||
*-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 a system call filter when *chronyd* is compiled with
|
||||
support for the Linux secure computing (seccomp) facility. In level 1 the
|
||||
process is killed when a forbidden system call is made, in level -1 the SIGSYS
|
||||
signal is thrown instead and in level 0 the filter is disabled. The default
|
||||
value is 0.
|
||||
+
|
||||
It is recommended to enable the filter only when it is known to work on the
|
||||
version of the system where *chrony* is installed as the filter needs to allow
|
||||
also system calls made from libraries that *chronyd* is using (e.g. libc) and
|
||||
different versions or implementations of the libraries might make different
|
||||
system calls. If the filter is missing some system call, *chronyd* could be
|
||||
killed even in normal operation.
|
||||
|
||||
*-P* _priority_::
|
||||
On Linux, this option will select the SCHED_FIFO real-time scheduler at the
|
||||
specified priority (which must be between 0 and 100). On macOS, this option
|
||||
must have either a value of 0 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.
|
||||
|
||||
*-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.
|
||||
|
||||
== FILES
|
||||
|
||||
_@SYSCONFDIR@/chrony.conf_
|
||||
|
||||
== SEE ALSO
|
||||
|
||||
<<chronyc.adoc#,*chronyc(1)*>>, <<chrony.conf.adoc#,*chrony.conf(5)*>>
|
||||
|
||||
== BUGS
|
||||
|
||||
For instructions on how to report bugs, please visit
|
||||
https://chrony.tuxfamily.org/.
|
||||
|
||||
== AUTHORS
|
||||
|
||||
chrony was written by Richard Curnow, Miroslav Lichvar, and others.
|
||||
676
doc/faq.adoc
676
doc/faq.adoc
@@ -1,676 +0,0 @@
|
||||
// This file is part of chrony
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Miroslav Lichvar 2014-2016, 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.
|
||||
|
||||
= Frequently Asked Questions
|
||||
:toc:
|
||||
:numbered:
|
||||
|
||||
== `chrony` compared to other programs
|
||||
|
||||
=== How does `chrony` compare to `ntpd`?
|
||||
|
||||
`chrony` and `ntpd` are two different implementations of the Network Time
|
||||
Protocol (NTP).
|
||||
|
||||
`chrony` is a newer implementation, which was designed to work well in a wider
|
||||
range of conditions. It can usually synchronise the system clock faster and
|
||||
with better time accuracy. It has many features, but it does not implement some
|
||||
of the less useful NTP modes like broadcast client or multicast server/client.
|
||||
|
||||
If your computer is connected to the Internet only for few minutes at a time,
|
||||
the network connection is often congested, you turn your computer off or
|
||||
suspend it frequently, the clock is not very stable (e.g. there are rapid
|
||||
changes in the temperature or it is a virtual machine), or you want to use NTP
|
||||
on an isolated network with no hardware reference clocks in sight, `chrony`
|
||||
will probably work better for you.
|
||||
|
||||
For a more detailed comparison of features and performance, see the
|
||||
https://chrony.tuxfamily.org/comparison.html[comparison page] on the `chrony`
|
||||
website.
|
||||
|
||||
== Configuration issues
|
||||
|
||||
=== What is the minimum recommended configuration for an NTP client?
|
||||
|
||||
First, the client needs to know which NTP servers it should ask for the current
|
||||
time. They are specified by the `server` or `pool` directive. The `pool`
|
||||
directive can be used for names that resolve to multiple addresses. For good
|
||||
reliability the client should have at least three servers. The `iburst` option
|
||||
speeds up the initial synchronisation.
|
||||
|
||||
To stabilise the initial synchronisation on the next start, the estimated drift
|
||||
of the system clock is saved to a file specified by the `driftfile` directive.
|
||||
|
||||
If the system clock can be far from the true time after boot for any reason,
|
||||
`chronyd` should be allowed to correct it quickly by stepping instead of
|
||||
slewing, which would take a very long time. The `makestep` directive does
|
||||
that.
|
||||
|
||||
In order to keep the real-time clock (RTC) close to the true time, so the
|
||||
system time is reasonably close to the true time when it is initialised on the
|
||||
next boot from the RTC, the `rtcsync` directive enables a mode in which the
|
||||
system time is periodically copied to the RTC. It is supported on Linux and
|
||||
macOS.
|
||||
|
||||
If you want to use public NTP servers from the
|
||||
https://www.pool.ntp.org/[pool.ntp.org] project, the minimal _chrony.conf_ file
|
||||
could be:
|
||||
|
||||
----
|
||||
pool pool.ntp.org iburst
|
||||
driftfile /var/lib/chrony/drift
|
||||
makestep 1 3
|
||||
rtcsync
|
||||
----
|
||||
|
||||
=== How do I make an NTP server?
|
||||
|
||||
You need to add an `allow` directive to the _chrony.conf_ file in order to open
|
||||
the NTP port and allow `chronyd` to reply to client requests. `allow` with no
|
||||
specified subnet allows access from all IPv4 and IPv6 addresses.
|
||||
|
||||
=== Should all computers on a LAN be clients of an external server?
|
||||
|
||||
It depends on the requirements. Usually, the best configuration is to make one
|
||||
computer the server, with the others as clients of it. Add a `local` directive
|
||||
to the server's _chrony.conf_ file. This configuration will be better because
|
||||
|
||||
* the load on the external connection is less
|
||||
* the load on the external NTP server(s) is less
|
||||
* if your external connection goes down, the computers on the LAN
|
||||
will maintain a common time with each other.
|
||||
|
||||
=== Must I specify servers by IP address if DNS is not available on `chronyd` start?
|
||||
|
||||
No, `chronyd` will keep trying to resolve
|
||||
the names specified by the `server`, `pool`, and `peer` directives in an
|
||||
increasing interval until it succeeds. The `online` command can be issued from
|
||||
`chronyc` to force `chronyd` to try to resolve the names immediately.
|
||||
|
||||
=== How can I make `chronyd` more secure?
|
||||
|
||||
If you do not need to use `chronyc`, or you want to run `chronyc` only
|
||||
under the root or _chrony_ user (which can access `chronyd` through a Unix
|
||||
domain socket), you can disable the IPv4 and IPv6 command sockets (by default
|
||||
listening on localhost) by adding `cmdport 0` to the configuration file.
|
||||
|
||||
You can specify an unprivileged user with the `-u` option, or the `user`
|
||||
directive in the _chrony.conf_ file, to which `chronyd` will switch after start
|
||||
in order to drop root privileges. The configure script has a `--with-user`
|
||||
option, which sets the default user. On Linux, `chronyd` needs to be compiled
|
||||
with support for the `libcap` library. On other systems, `chronyd` forks into
|
||||
two processes. The child process retains root privileges, but can only perform
|
||||
a very limited range of privileged system calls on behalf of the parent.
|
||||
|
||||
Also, if `chronyd` is compiled with support for the Linux secure computing
|
||||
(seccomp) facility, you can enable a system call filter with the `-F` option.
|
||||
It will significantly reduce the kernel attack surface and possibly prevent
|
||||
kernel exploits from the `chronyd` process if it is compromised. It is
|
||||
recommended to enable the filter only when it is known to work on the version of
|
||||
the system where `chrony` is installed as the filter needs to allow also system
|
||||
calls made from libraries that `chronyd` is using (e.g. libc) and different
|
||||
versions or implementations of the libraries might make different system calls.
|
||||
If the filter is missing some system call, `chronyd` could be killed even in
|
||||
normal operation.
|
||||
|
||||
=== How can I improve the accuracy of the system clock with NTP sources?
|
||||
|
||||
Select NTP servers that are well synchronised, stable and close to your
|
||||
network. It is better to use more than one server, three or four is usually
|
||||
recommended as the minimum, so `chronyd` can detect servers that serve false
|
||||
time and combine measurements from multiple sources.
|
||||
|
||||
If you have a network card with hardware timestamping supported on Linux, it
|
||||
can be enabled by the `hwtimestamp` directive in the _chrony.conf_ file. It
|
||||
should make local receive and transmit timestamps of NTP packets much more
|
||||
accurate.
|
||||
|
||||
There are also useful options which can be set in the `server` directive, they
|
||||
are `minpoll`, `maxpoll`, `polltarget`, `maxdelay`, `maxdelayratio`,
|
||||
`maxdelaydevratio`, and `xleave`.
|
||||
|
||||
The first three options set the minimum and maximum allowed polling interval,
|
||||
and how should be the actual interval adjusted in the specified range. Their
|
||||
default values are 6 (64 seconds) for `minpoll`, 10 (1024 seconds) for
|
||||
`maxpoll` and 8 (samples) for `polltarget`. The default values should be used
|
||||
for general servers on the Internet. With your own NTP servers, or if you have
|
||||
permission to poll some servers more frequently, setting these options for
|
||||
shorter polling intervals might significantly improve the accuracy of the
|
||||
system clock.
|
||||
|
||||
The optimal polling interval depends mainly on two factors, stability of the
|
||||
network latency and stability of the system clock (which mainly depends on the
|
||||
temperature sensitivity of the crystal oscillator and the maximum rate of the
|
||||
temperature change).
|
||||
|
||||
Generally, if the `sourcestats` command usually reports a small number of
|
||||
samples retained for a source (e.g. fewer than 16), a shorter polling interval
|
||||
should be considered. If the number of samples is usually at the maximum of 64,
|
||||
a longer polling interval might work better.
|
||||
|
||||
An example of the directive for an NTP server on the Internet that you are
|
||||
allowed to poll frequently could be
|
||||
|
||||
----
|
||||
server foo.example.net minpoll 4 maxpoll 6 polltarget 16
|
||||
----
|
||||
|
||||
An example using shorter polling intervals with a server located in the same
|
||||
LAN could be
|
||||
|
||||
----
|
||||
server ntp.local minpoll 2 maxpoll 4 polltarget 30
|
||||
----
|
||||
|
||||
The maxdelay options are useful to ignore measurements with an unusally large
|
||||
delay (e.g. due to congestion in the network) and improve the stability of the
|
||||
synchronisation. The `maxdelaydevratio` option could be added to the example
|
||||
with local NTP server
|
||||
|
||||
----
|
||||
server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
|
||||
----
|
||||
|
||||
If your server supports the interleaved mode (e.g. it is running `chronyd`),
|
||||
the `xleave` option should be added to the `server` directive in order to allow
|
||||
the server to send the client more accurate transmit timestamps (kernel or
|
||||
preferably hardware). For example:
|
||||
|
||||
----
|
||||
server ntp.local minpoll 2 maxpoll 4 xleave
|
||||
----
|
||||
|
||||
When combined with local hardware timestamping, good network switches, and even
|
||||
shorter polling intervals, a sub-microsecond accuracy and stability of a few
|
||||
tens of nanoseconds might be possible. For example:
|
||||
|
||||
----
|
||||
server ntp.local minpoll 0 maxpoll 0 xleave
|
||||
hwtimestamp eth0
|
||||
----
|
||||
|
||||
For best stability, the CPU should be running at a constant frequency (i.e.
|
||||
disabled power saving and performance boosting). Energy-Efficient Ethernet
|
||||
(EEE) should be disabled in the network. The switches should be configured to
|
||||
prioritize NTP packets, especially if the network is expected to be heavily
|
||||
loaded. The `dscp` directive can be used to set the Differentiated Services
|
||||
Code Point in transmitted NTP packets if needed.
|
||||
|
||||
If it is acceptable for NTP clients in the network to send requests at a high
|
||||
rate, a sub-second polling interval can be specified. A median filter
|
||||
can be enabled in order to update the clock at a reduced rate with more stable
|
||||
measurements. For example:
|
||||
|
||||
----
|
||||
server ntp.local minpoll -6 maxpoll -6 filter 15 xleave
|
||||
hwtimestamp eth0 minpoll -6
|
||||
----
|
||||
|
||||
=== Does `chronyd` have an ntpdate mode?
|
||||
|
||||
Yes. With the `-q` option `chronyd` will set the system clock once and exit.
|
||||
With the `-Q` option it will print the measured offset without setting the
|
||||
clock. If you do not want to use a configuration file, NTP servers can be
|
||||
specified on the command line. For example:
|
||||
|
||||
----
|
||||
# chronyd -q 'pool pool.ntp.org iburst'
|
||||
----
|
||||
|
||||
The command above would normally take about 5 seconds if the servers were
|
||||
well synchronised and responding to all requests. If not synchronised or
|
||||
responding, it would take about 10 seconds for `chronyd` to give up and exit
|
||||
with a non-zero status. A faster configuration is possible. A single server can
|
||||
be used instead of four servers, the number of measurements can be reduced with
|
||||
the `maxsamples` option to one (supported in `chrony` version 4.0), and a
|
||||
timeout can be specified with the `-t` option. The following command would take
|
||||
only up to about one second.
|
||||
|
||||
----
|
||||
# chronyd -q -t 1 'server pool.ntp.org iburst maxsamples 1'
|
||||
----
|
||||
|
||||
It is not recommended to run `chronyd` with the `-q` option periodically (e.g.
|
||||
from a cron job) as a replacement for the daemon mode, because it performs
|
||||
significantly worse (e.g. the clock is stepped and its frequency is not
|
||||
corrected). If you must run it this way and you are using a public NTP server,
|
||||
make sure `chronyd` does not always start around the first second of a minute,
|
||||
e.g. by adding a random sleep before the `chronyd` command. Public servers
|
||||
typically receive large bursts of requests around the first second as there is
|
||||
a large number of NTP clients started from cron with no delay.
|
||||
|
||||
=== Can `chronyd` be configured to control the clock like `ntpd`?
|
||||
|
||||
It is not possible to perfectly emulate `ntpd`, but there are some options that
|
||||
can configure `chronyd` to behave more like `ntpd` if there is a reason to
|
||||
prefer that.
|
||||
|
||||
In the following example the `minsamples` directive slows down the response to
|
||||
changes in the frequency and offset of the clock. The `maxslewrate` and
|
||||
`corrtimeratio` directives reduce the maximum frequency error due to an offset
|
||||
correction and the `maxdrift` directive reduces the maximum assumed frequency
|
||||
error of the clock. The `makestep` directive enables a step threshold and the
|
||||
`maxchange` directive enables a panic threshold. The `maxclockerror` directive
|
||||
increases the minimum dispersion rate.
|
||||
|
||||
----
|
||||
minsamples 32
|
||||
maxslewrate 500
|
||||
corrtimeratio 100
|
||||
maxdrift 500
|
||||
makestep 0.128 -1
|
||||
maxchange 1000 1 1
|
||||
maxclockerror 15
|
||||
----
|
||||
|
||||
Note that increasing `minsamples` might cause the offsets in the `tracking` and
|
||||
`sourcestats` reports/logs to be significantly smaller than the actual offsets
|
||||
and be unsuitable for monitoring.
|
||||
|
||||
=== Can NTP server be separated from NTP client?
|
||||
|
||||
Yes, it is possible to run multiple instances of `chronyd` on the same
|
||||
computer. One can be configured as an NTP client, and another as a server. They
|
||||
need to use different pidfiles, NTP ports, command ports, and Unix domain
|
||||
command sockets. The server instance should be started with the `-x` option to
|
||||
avoid touching the clock. It can be configured to serve the system time with
|
||||
the `local` directive, or synchronise its NTP clock to the client instance
|
||||
running on localhost using a non-standard NTP port.
|
||||
|
||||
On Linux, starting with `chrony` version 4.0, it is also possible to run
|
||||
multiple server instances sharing a port to utilise multiple cores of the CPU.
|
||||
Note that the client/server interleaved mode requires that all packets from an
|
||||
address are handled by the same server instance.
|
||||
|
||||
=== Should be a leap smear enabled on NTP server?
|
||||
|
||||
With the `smoothtime` and `leapsecmode` directives it is possible to enable a
|
||||
server leap smear in order to hide leap seconds from clients and force them to
|
||||
follow a slow server's adjustment instead.
|
||||
|
||||
This feature should be used only in local networks and only when necessary,
|
||||
e.g. when the clients cannot be configured to handle the leap seconds as
|
||||
needed, or their number is so large that configuring them all would be
|
||||
impractical. The clients should use only one leap-smearing server, or multiple
|
||||
identically configured leap-smearing servers. Note that some clients can get
|
||||
leap seconds from external sources (e.g. with the `leapsectz` directive in
|
||||
`chrony`) and they will not work correctly with a leap smearing server.
|
||||
|
||||
=== Does `chrony` support PTP?
|
||||
|
||||
No, the Precision Time Protocol (PTP) is not supported and there are no plans
|
||||
to support it. It is a complex protocol, which shares some issues with the
|
||||
NTP broadcast mode. One of the main differences between NTP and PTP is that PTP
|
||||
was designed to be easily supported in hardware (e.g. network switches and
|
||||
routers) in order to make more stable and accurate measurements. PTP relies on
|
||||
the hardware support. NTP does not rely on any support in the hardware, but if
|
||||
it had the same support as PTP, it could perform equally well.
|
||||
|
||||
On Linux, `chrony` supports hardware clocks that some NICs have for PTP. They
|
||||
are called PTP hardware clocks (PHC). They can be used as reference clocks
|
||||
(specified by the `refclock` directive) and for hardware timestamping of NTP
|
||||
packets (enabled by the `hwtimestamp` directive) if the NIC can timestamp other
|
||||
packets than PTP, which is usually the case at least for transmitted packets.
|
||||
The `ethtool -T` command can be used to verify the timestamping support.
|
||||
|
||||
=== What happened to the `commandkey` and `generatecommandkey` directives?
|
||||
|
||||
They were removed in version 2.2. Authentication is no longer supported in the
|
||||
command protocol. Commands that required authentication are now allowed only
|
||||
through a Unix domain socket, which is accessible only by the root and _chrony_
|
||||
users. If you need to configure `chronyd` remotely or locally without the root
|
||||
password, please consider using ssh and/or sudo to run `chronyc` under the root
|
||||
or _chrony_ user on the host where `chronyd` is running.
|
||||
|
||||
== Computer is not synchronising
|
||||
|
||||
This is the most common problem. There are a number of reasons, see the
|
||||
following questions.
|
||||
|
||||
=== Behind a firewall?
|
||||
|
||||
Check the `Reach` value printed by the ``chronyc``'s `sources` command. If it
|
||||
is zero, it means `chronyd` did not get any valid responses from the NTP server
|
||||
you are trying to use. If there is a firewall between you and the server, the
|
||||
packets might be blocked. Try using a tool like `wireshark` or `tcpdump` to see
|
||||
if you are getting any responses from the server.
|
||||
|
||||
When `chronyd` is receiving responses from the servers, the output of the
|
||||
`sources` command issued few minutes after `chronyd` start might look like
|
||||
this:
|
||||
|
||||
----
|
||||
210 Number of sources = 3
|
||||
MS Name/IP address Stratum Poll Reach LastRx Last sample
|
||||
===============================================================================
|
||||
^* foo.example.net 2 6 377 34 +484us[ -157us] +/- 30ms
|
||||
^- bar.example.net 2 6 377 34 +33ms[ +32ms] +/- 47ms
|
||||
^+ baz.example.net 3 6 377 35 -1397us[-2033us] +/- 60ms
|
||||
----
|
||||
|
||||
=== Are NTP servers specified with the `offline` option?
|
||||
|
||||
Check that the ``chronyc``'s `online` and `offline` commands are used
|
||||
appropriately (e.g. in the system networking scripts). The `activity` command
|
||||
prints the number of sources that are currently online and offline. For
|
||||
example:
|
||||
|
||||
----
|
||||
200 OK
|
||||
3 sources online
|
||||
0 sources offline
|
||||
0 sources doing burst (return to online)
|
||||
0 sources doing burst (return to offline)
|
||||
0 sources with unknown address
|
||||
----
|
||||
|
||||
=== Is `chronyd` allowed to step the system clock?
|
||||
|
||||
By default, `chronyd` adjusts the clock gradually by slowing it down or
|
||||
speeding it up. If the clock is too far from the true time, it will take
|
||||
a long time to correct the error. The `System time` value printed by the
|
||||
``chronyc``'s `tracking` command is the remaining correction that needs to be
|
||||
applied to the system clock.
|
||||
|
||||
The `makestep` directive can be used to allow `chronyd` to step the clock. For
|
||||
example, if _chrony.conf_ had
|
||||
|
||||
----
|
||||
makestep 1 3
|
||||
----
|
||||
|
||||
the clock would be stepped in the first three updates if its offset was larger
|
||||
than one second. Normally, it is recommended to allow the step only in the first
|
||||
few updates, but in some cases (e.g. a computer without an RTC or virtual
|
||||
machine which can be suspended and resumed with an incorrect time) it might be
|
||||
necessary to allow the step on any clock update. The example above would change
|
||||
to
|
||||
|
||||
----
|
||||
makestep 1 -1
|
||||
----
|
||||
|
||||
=== Using a Windows NTP server?
|
||||
|
||||
A common issue with Windows NTP servers is that they report a very large root
|
||||
dispersion (e.g. three seconds or more), which causes `chronyd` to ignore the
|
||||
server for being too inaccurate. The `sources` command might show a valid
|
||||
measurement, but the server is not selected for synchronisation. You can check
|
||||
the root dispersion of the server with the ``chronyc``'s `ntpdata` command.
|
||||
|
||||
The `maxdistance` value needs to be increased in _chrony.conf_ to enable
|
||||
synchronisation to such a server. For example:
|
||||
|
||||
----
|
||||
maxdistance 16.0
|
||||
----
|
||||
|
||||
=== An unreachable source is selected?
|
||||
|
||||
When `chronyd` is configured with multiple time sources, it tries to select the
|
||||
most accurate and stable sources for synchronisation of the system clock. They
|
||||
are marked with the _*_ or _+_ symbol in the report printed by the `sources`
|
||||
command.
|
||||
|
||||
When the best source (marked with the _*_ symbol) becomes unreachable (e.g. NTP
|
||||
server stops responding), `chronyd` will not immediately switch
|
||||
to the second best source in an attempt to minimise the error of the clock. It
|
||||
will let the clock run free for as long as its estimated error (in terms of
|
||||
root distance) based on previous measurements is smaller than the estimated
|
||||
error of the second source, and there is still an interval which contains some
|
||||
measurements from both sources.
|
||||
|
||||
If the first source was significantly better than the second source, it can
|
||||
take many hours before the second source is selected, depending on its polling
|
||||
interval. You can force a faster reselection by increasing the clock error rate
|
||||
(`maxclockerror` directive), shortening the polling interval (`maxpoll`
|
||||
option), or reducing the number of samples (`maxsamples` option).
|
||||
|
||||
=== Does selected source drop new measurements?
|
||||
|
||||
`chronyd` can drop a large number of successive NTP measurements if they are
|
||||
not passing some of the NTP tests. The `sources` command can report for a
|
||||
selected source the fully-reachable value of 377 in the Reach column and at the
|
||||
same time a LastRx value that is much larger than the current polling interval.
|
||||
If the source is online, this indicates that a number of measurements was
|
||||
dropped. You can use the `ntpdata` command to check the NTP tests for the last
|
||||
measurement. Usually, it is the test C which fails.
|
||||
|
||||
This can be an issue when there is a long-lasting increase in the measured
|
||||
delay, e.g. due to a routing change in the network. Unfortunately, `chronyd`
|
||||
does not know for how long it should wait for the delay to come back to the
|
||||
original values, or whether it is a permanent increase and it should start from
|
||||
scratch.
|
||||
|
||||
The test C is an adaptive filter. It can take many hours before it accepts
|
||||
a measurement with the larger delay, and even much longer before it drops all
|
||||
measurements with smaller delay, which determine an expected delay used by the
|
||||
test. You can use the `reset sources` command to drop all measurements
|
||||
immediately (available in chrony 4.0 and later). If this issue happens
|
||||
frequently, you can effectively disable the test by setting the
|
||||
`maxdelaydevratio` option to a very large value (e.g. 1000000), or speed up the
|
||||
recovery by increasing the clock error rate with the `maxclockerror` directive.
|
||||
|
||||
=== Using a PPS reference clock?
|
||||
|
||||
A pulse-per-second (PPS) reference clock requires a non-PPS time source to
|
||||
determine which second of UTC corresponds to each pulse. If it is another
|
||||
reference clock specified with the `lock` option in the `refclock` directive,
|
||||
the offset between the two reference clocks must be smaller than 0.2 seconds in
|
||||
order for the PPS reference clock to work. With NMEA reference clocks it is
|
||||
common to have a larger offset. It needs to be corrected with the `offset`
|
||||
option.
|
||||
|
||||
One approach to find out a good value of the `offset` option is to configure
|
||||
the reference clocks with the `noselect` option and compare them to an NTP
|
||||
server. For example, if the `sourcestats` command showed
|
||||
|
||||
----
|
||||
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
|
||||
==============================================================================
|
||||
PPS0 0 0 0 +0.000 2000.000 +0ns 4000ms
|
||||
NMEA 58 30 231 -96.494 38.406 +504ms 6080us
|
||||
foo.example.net 7 3 200 -2.991 16.141 -107us 492us
|
||||
----
|
||||
|
||||
the offset of the NMEA source would need to be increased by about 0.504
|
||||
seconds. It does not have to be very accurate. As long as the offset of the
|
||||
NMEA reference clock stays below 0.2 seconds, the PPS reference clock should be
|
||||
able to determine the seconds corresponding to the pulses and allow the samples
|
||||
to be used for synchronisation.
|
||||
|
||||
== Issues with `chronyc`
|
||||
|
||||
=== I keep getting the error `506 Cannot talk to daemon`
|
||||
|
||||
When accessing `chronyd` remotely, make sure that the _chrony.conf_ file (on
|
||||
the computer where `chronyd` is running) has a `cmdallow` entry for the
|
||||
computer you are running `chronyc` on and an appropriate `bindcmdaddress`
|
||||
directive. This is not necessary for localhost.
|
||||
|
||||
Perhaps `chronyd` is not running. Try using the `ps` command (e.g. on Linux,
|
||||
`ps -auxw`) to see if it is running. Or try `netstat -a` and see if the UDP
|
||||
port 323 is listening. If `chronyd` is not running, you might have a problem
|
||||
with the way you are trying to start it (e.g. at boot time).
|
||||
|
||||
Perhaps you have a firewall set up in a way that blocks packets on the UDP
|
||||
port 323. You need to amend the firewall configuration in this case.
|
||||
|
||||
=== I keep getting the error `501 Not authorised`
|
||||
|
||||
This error indicates that `chronyc` sent the command to `chronyd` using a UDP
|
||||
socket instead of the Unix domain socket (e.g. _/var/run/chrony/chronyd.sock_),
|
||||
which is required for some commands. For security reasons, only the root and
|
||||
_chrony_ users are allowed to access the socket.
|
||||
|
||||
It is also possible that the socket does not exist. `chronyd` will not create
|
||||
the socket if the directory has a wrong owner or permissions. In this case
|
||||
there should be an error message from `chronyd` in the system log.
|
||||
|
||||
=== What is the reference ID reported by the `tracking` command?
|
||||
|
||||
The reference ID is a 32-bit value used in NTP to prevent synchronisation
|
||||
loops.
|
||||
|
||||
In `chrony` versions before 3.0 it was printed in the
|
||||
quad-dotted notation, even if the reference source did not actually have an
|
||||
IPv4 address. For IPv4 addresses, the reference ID is equal to the address, but
|
||||
for IPv6 addresses it is the first 32 bits of the MD5 sum of the address. For
|
||||
reference clocks, the reference ID is the value specified with the `refid`
|
||||
option in the `refclock` directive.
|
||||
|
||||
Since version 3.0, the reference ID is printed as a hexadecimal number to avoid
|
||||
confusion with IPv4 addresses.
|
||||
|
||||
If you need to get the IP address of the current reference source, use the `-n`
|
||||
option to disable resolving of IP addresses and read the second field (printed
|
||||
in parentheses) on the `Reference ID` line.
|
||||
|
||||
=== Is the `chronyc` / `chronyd` protocol documented anywhere?
|
||||
|
||||
Only by the source code. See _cmdmon.c_ (`chronyd` side) and _client.c_
|
||||
(`chronyc` side).
|
||||
|
||||
== Real-time clock issues
|
||||
|
||||
=== What is the real-time clock (RTC)?
|
||||
|
||||
This is the clock which keeps the time even when your computer is turned off.
|
||||
It is used to initialise the system clock on boot. It normally does not drift
|
||||
more than few seconds per day.
|
||||
|
||||
There are two approaches how `chronyd` can work with it. One is to use the
|
||||
`rtcsync` directive, which tells `chronyd` to enable a kernel mode which sets
|
||||
the RTC from the system clock every 11 minutes. `chronyd` itself won't touch
|
||||
the RTC. If the computer is not turned off for a long time, the RTC should
|
||||
still be close to the true time when the system clock will be initialised from
|
||||
it on the next boot.
|
||||
|
||||
The other option is to use the `rtcfile` directive, which tells `chronyd` to
|
||||
monitor the rate at which the RTC gains or loses time. When `chronyd` is
|
||||
started with the `-s` option on the next boot, it will set the system time from
|
||||
the RTC and also compensate for the drift it has measured previously. The
|
||||
`rtcautotrim` directive can be used to keep the RTC close to the true time, but
|
||||
it is not strictly necessary if its only purpose is to set the system clock when
|
||||
`chronyd` is started on boot. See the documentation for details.
|
||||
|
||||
=== Does `hwclock` have to be disabled?
|
||||
|
||||
The `hwclock` program is often set-up by default in the boot and shutdown
|
||||
scripts with many Linux installations. With the kernel RTC synchronisation
|
||||
(`rtcsync` directive), the RTC will be set also every 11 minutes as long as the
|
||||
system clock is synchronised. If you want to use ``chronyd``'s RTC monitoring
|
||||
(`rtcfile` directive), it is important to disable `hwclock` in the shutdown
|
||||
procedure. If you do not that, it will over-write the RTC with a new value, unknown
|
||||
to `chronyd`. At the next reboot, `chronyd` started with the `-s` option will
|
||||
compensate this (wrong) time with its estimate of how far the RTC has drifted
|
||||
whilst the power was off, giving a meaningless initial system time.
|
||||
|
||||
There is no need to remove `hwclock` from the boot process, as long as `chronyd`
|
||||
is started after it has run.
|
||||
|
||||
=== I just keep getting the `513 RTC driver not running` message
|
||||
|
||||
For the real-time clock support to work, you need the following three
|
||||
things
|
||||
|
||||
* an RTC in your computer
|
||||
* a Linux kernel with enabled RTC support
|
||||
* an `rtcfile` directive in your _chrony.conf_ file
|
||||
|
||||
=== I get `Could not open /dev/rtc, Device or resource busy` in my syslog file
|
||||
|
||||
Some other program running on the system might be using the device.
|
||||
|
||||
=== What if my computer does not have an RTC or backup battery?
|
||||
|
||||
In this case you can still use the `-s` option to set the system clock to the
|
||||
last modification time of the drift file, which should correspond to the system
|
||||
time when `chronyd` was previously stopped. The initial system time will be
|
||||
increasing across reboots and applications started after `chronyd` will not
|
||||
observe backward steps.
|
||||
|
||||
== NTP-specific issues
|
||||
|
||||
=== Can `chronyd` be driven from broadcast/multicast NTP servers?
|
||||
|
||||
No, the broadcast/multicast client mode is not supported and there is currently
|
||||
no plan to implement it. While this mode can simplify configuration
|
||||
of clients in large networks, it is inherently less accurate and less secure
|
||||
(even with authentication) than the ordinary client/server mode.
|
||||
|
||||
When configuring a large number of clients in a network, it is recommended to
|
||||
use the `pool` directive with a DNS name which resolves to addresses of
|
||||
multiple NTP servers. The clients will automatically replace the servers when
|
||||
they become unreachable, or otherwise unsuitable for synchronisation, with new
|
||||
servers from the pool.
|
||||
|
||||
Even with very modest hardware, an NTP server can serve time to hundreds of
|
||||
thousands of clients using the ordinary client/server mode.
|
||||
|
||||
=== Can `chronyd` transmit broadcast NTP packets?
|
||||
|
||||
Yes, the `broadcast` directive can be used to enable the broadcast server mode
|
||||
to serve time to clients in the network which support the broadcast client mode
|
||||
(it is not supported in `chronyd`). Note that this mode should generally be
|
||||
avoided. See the previous question.
|
||||
|
||||
=== Can `chronyd` keep the system clock a fixed offset away from real time?
|
||||
|
||||
Yes. Starting from version 3.0, an offset can be specified by the `offset`
|
||||
option for all time sources in the _chrony.conf_ file.
|
||||
|
||||
=== What happens if the network connection is dropped without using ``chronyc``'s `offline` command first?
|
||||
|
||||
`chronyd` will keep trying to access the sources that it thinks are online, and
|
||||
it will take longer before new measurements are actually made and the clock is
|
||||
corrected when the network is connected again. If the sources were set to
|
||||
offline, `chronyd` would make new measurements immediately after issuing the
|
||||
`online` command.
|
||||
|
||||
Unless the network connection lasts only few minutes (less than the maximum
|
||||
polling interval), the delay is usually not a problem, and it might be acceptable
|
||||
to keep all sources online all the time.
|
||||
|
||||
=== Why is an offset measured between two computers synchronised to each another?
|
||||
|
||||
When two computers are synchronised to each other using the client/server or
|
||||
symmetric NTP mode, there is an expectation that NTP measurements between the
|
||||
two computers made on both ends show an average offset close to zero.
|
||||
|
||||
With `chronyd` that can be expected only when the interleaved mode (`xleave`
|
||||
option) is enabled. Otherwise, `chronyd` will use different transmit timestamps
|
||||
(e.g. daemon timestamp vs kernel timestamp) for serving time and
|
||||
synchronisation of its own clock, which creates an asymmetry in the
|
||||
timestamping and causes the other end to measure a significant offset.
|
||||
|
||||
== Operating systems
|
||||
|
||||
=== Does `chrony` support Windows?
|
||||
|
||||
No. The `chronyc` program (the command-line client used for configuring
|
||||
`chronyd` while it is running) has been successfully built and run under
|
||||
Cygwin in the past. `chronyd` is not portable, because part of it is
|
||||
very system-dependent. It needs adapting to work with Windows'
|
||||
equivalent of the adjtimex() call, and it needs to be made to work as a
|
||||
service.
|
||||
|
||||
=== Are there any plans to support Windows?
|
||||
|
||||
We have no plans to do this. Anyone is welcome to pick this work up and
|
||||
contribute it back to the project.
|
||||
@@ -1,200 +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, 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 POSIX threads library are available, `chronyd`
|
||||
will be built with support for asynchronous resolving of hostnames specified in
|
||||
the `server`, `peer`, and `pool` directives. This allows `chronyd` operating as
|
||||
a server to respond to client requests when resolving a hostname. If you don't
|
||||
want to enable the support, specify the `--disable-asyncdns` flag to
|
||||
`configure`.
|
||||
|
||||
If development files for the https://www.lysator.liu.se/~nisse/nettle/[Nettle],
|
||||
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS[NSS], or
|
||||
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.
|
||||
@@ -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,11 +7,9 @@ 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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -27,50 +43,44 @@
|
||||
# you can access at http://support.ntp.org/bin/view/Servers/WebHome or
|
||||
# you can use servers from the pool.ntp.org project.
|
||||
|
||||
! server foo.example.net iburst
|
||||
! server bar.example.net iburst
|
||||
! server baz.example.net iburst
|
||||
|
||||
! pool pool.ntp.org iburst
|
||||
! 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.
|
||||
@@ -81,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/.../foo.example.net.crt
|
||||
! ntsserverkey /etc/.../foo.example.net.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
|
||||
@@ -124,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
|
||||
|
||||
# If the system timezone database is kept up to date and includes the
|
||||
# right/UTC timezone, chronyd can use it to determine the current
|
||||
# TAI-UTC offset and when will the next leap second occur.
|
||||
|
||||
! leapsectz right/UTC
|
||||
! 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
|
||||
@@ -176,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.
|
||||
@@ -191,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
|
||||
@@ -205,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
|
||||
@@ -238,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@foo.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
|
||||
@@ -263,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
|
||||
@@ -307,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
|
||||
@@ -1,12 +0,0 @@
|
||||
# Use public NTP servers from the pool.ntp.org project.
|
||||
pool pool.ntp.org iburst
|
||||
|
||||
# Record the rate at which the system clock gains/losses time.
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# Allow the system clock to be stepped in the first three updates
|
||||
# if its offset is larger than 1 second.
|
||||
makestep 1.0 3
|
||||
|
||||
# Enable kernel synchronization of the real-time clock (RTC).
|
||||
rtcsync
|
||||
@@ -1,47 +1,46 @@
|
||||
# Use public servers from the pool.ntp.org project.
|
||||
# Please consider joining the pool (https://www.pool.ntp.org/join.html).
|
||||
pool pool.ntp.org iburst
|
||||
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
|
||||
server 0.pool.ntp.org iburst
|
||||
server 1.pool.ntp.org iburst
|
||||
server 2.pool.ntp.org iburst
|
||||
server 3.pool.ntp.org iburst
|
||||
|
||||
# Ignore stratum in source selection.
|
||||
stratumweight 0
|
||||
|
||||
# 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
|
||||
|
||||
# Get TAI-UTC offset and leap seconds from the system tz database.
|
||||
#leapsectz right/UTC
|
||||
# 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
|
||||
|
||||
@@ -1,13 +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
|
||||
#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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
17
examples/chrony.nm-dispatcher
Normal file
17
examples/chrony.nm-dispatcher
Normal 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
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/bin/sh
|
||||
# This is a NetworkManager dispatcher script for chronyd to update
|
||||
# its NTP sources passed from DHCP options. Note that this script is
|
||||
# specific to NetworkManager-dispatcher due to use of the
|
||||
# DHCP4_NTP_SERVERS environment variable.
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
interface=$1
|
||||
action=$2
|
||||
|
||||
chronyc=/usr/bin/chronyc
|
||||
default_server_options=iburst
|
||||
server_dir=/var/run/chrony-dhcp
|
||||
|
||||
dhcp_server_file=$server_dir/$interface.sources
|
||||
# DHCP4_NTP_SERVERS is passed from DHCP options by NetworkManager.
|
||||
nm_dhcp_servers=$DHCP4_NTP_SERVERS
|
||||
|
||||
add_servers_from_dhcp() {
|
||||
rm -f "$dhcp_server_file"
|
||||
for server in $nm_dhcp_servers; do
|
||||
echo "server $server $default_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
|
||||
|
||||
if [ "$action" = "up" ] || [ "$action" = "dhcp4-change" ]; then
|
||||
add_servers_from_dhcp
|
||||
elif [ "$action" = "down" ]; then
|
||||
clear_servers_from_dhcp
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -1,17 +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 up/down events
|
||||
[ $# -ge 2 ] && [ "$2" != "up" ] && [ "$2" != "down" ] && exit 0
|
||||
|
||||
# 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
57
examples/chrony.spec
Normal 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
|
||||
|
||||
@@ -1,18 +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=forking
|
||||
PIDFile=/run/chrony/chronyd.pid
|
||||
PIDFile=/var/run/chronyd.pid
|
||||
EnvironmentFile=-/etc/sysconfig/chronyd
|
||||
ExecStart=/usr/sbin/chronyd $OPTIONS
|
||||
PrivateTmp=yes
|
||||
ProtectHome=yes
|
||||
ProtectSystem=full
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
@@ -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
|
||||
|
||||
25
hash.h
25
hash.h
@@ -31,26 +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_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
|
||||
|
||||
@@ -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)
|
||||
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;
|
||||
}
|
||||
|
||||
121
hash_nettle.c
121
hash_nettle.c
@@ -1,121 +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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
58
hash_nss.c
58
hash_nss.c
@@ -25,43 +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;
|
||||
|
||||
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()))
|
||||
@@ -74,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);
|
||||
}
|
||||
|
||||
@@ -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,54 +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;
|
||||
|
||||
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);
|
||||
@@ -89,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)
|
||||
{
|
||||
}
|
||||
|
||||
227
hwclock.c
227
hwclock.c
@@ -1,227 +0,0 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016-2018
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Tracking of hardware clocks (e.g. RTC, PHC)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "array.h"
|
||||
#include "hwclock.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "regress.h"
|
||||
#include "util.h"
|
||||
|
||||
/* 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)
|
||||
|
||||
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;
|
||||
|
||||
/* Flag indicating the offset and frequency values are valid */
|
||||
int valid_coefs;
|
||||
|
||||
/* Estimated offset and frequency of HW clock relative to local clock */
|
||||
double offset;
|
||||
double frequency;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
|
||||
double doffset, LCL_ChangeType change_type, void *anything)
|
||||
{
|
||||
HCL_Instance clock;
|
||||
double delta;
|
||||
|
||||
clock = anything;
|
||||
|
||||
if (clock->n_samples)
|
||||
UTI_AdjustTimespec(&clock->local_ref, cooked, &clock->local_ref, &delta, dfreq, doffset);
|
||||
if (clock->valid_coefs)
|
||||
clock->frequency /= 1.0 - dfreq;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
HCL_Instance
|
||||
HCL_CreateInstance(int min_samples, int max_samples, double min_separation)
|
||||
{
|
||||
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;
|
||||
|
||||
LCL_AddParameterChangeHandler(handle_slew, clock);
|
||||
|
||||
return clock;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void HCL_DestroyInstance(HCL_Instance clock)
|
||||
{
|
||||
LCL_RemoveParameterChangeHandler(handle_slew, clock);
|
||||
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;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
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;
|
||||
}
|
||||
49
hwclock.h
49
hwclock.h
@@ -1,49 +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);
|
||||
|
||||
/* Destroy a HW clock instance */
|
||||
extern void HCL_DestroyInstance(HCL_Instance clock);
|
||||
|
||||
/* Check if a new sample should be accumulated at this time */
|
||||
extern int HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now);
|
||||
|
||||
/* Accumulate a new sample */
|
||||
extern void HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
||||
struct timespec *local_ts, double err);
|
||||
|
||||
/* Convert raw hardware time to cooked local time */
|
||||
extern int HCL_CookTime(HCL_Instance clock, struct timespec *raw, struct timespec *cooked,
|
||||
double *err);
|
||||
|
||||
#endif
|
||||
380
keys.c
380
keys.c
@@ -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,9 +214,9 @@ KEY_Reload(void)
|
||||
if (!key_file)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -195,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);
|
||||
@@ -253,47 +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);
|
||||
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);
|
||||
|
||||
@@ -301,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 && !memcmp(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
19
keys.h
@@ -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 */
|
||||
|
||||
243
local.c
243
local.c
@@ -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;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -106,36 +101,40 @@ static double max_clock_error;
|
||||
under 1s of busy waiting. */
|
||||
#define NITERS 100
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
static double
|
||||
measure_clock_precision(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 1.0e-9 * 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;
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOGF_Local, "Clock precision %.9f (%d)", precision_quantum, precision_log);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -159,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;
|
||||
}
|
||||
@@ -183,11 +168,6 @@ LCL_Initialise(void)
|
||||
void
|
||||
LCL_Finalise(void)
|
||||
{
|
||||
/* Make sure all handlers have been removed */
|
||||
if (change_list.next != &change_list)
|
||||
assert(0);
|
||||
if (dispersion_notify_list.next != &dispersion_notify_list)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -267,7 +247,7 @@ void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *
|
||||
ptr->next->prev = ptr->prev;
|
||||
ptr->prev->next = ptr->next;
|
||||
|
||||
Free(ptr);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -281,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)
|
||||
{
|
||||
@@ -344,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);
|
||||
@@ -379,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);
|
||||
@@ -415,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;
|
||||
@@ -479,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;
|
||||
@@ -490,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);
|
||||
@@ -508,7 +451,7 @@ LCL_AccumulateDeltaFrequency(double dfreq)
|
||||
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 */
|
||||
@@ -516,9 +459,6 @@ LCL_AccumulateOffset(double offset, double corr_rate)
|
||||
LCL_ReadRawTime(&raw);
|
||||
LCL_CookTime(&raw, &cooked, NULL);
|
||||
|
||||
if (!check_offset(&cooked, offset))
|
||||
return;
|
||||
|
||||
(*drv_accrue_offset)(offset, corr_rate);
|
||||
|
||||
/* Dispatch to all handlers */
|
||||
@@ -527,10 +467,10 @@ LCL_AccumulateOffset(double offset, double corr_rate)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
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 */
|
||||
@@ -538,27 +478,16 @@ 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)
|
||||
{
|
||||
/* Dispatch to all handlers */
|
||||
@@ -569,27 +498,10 @@ 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);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
|
||||
{
|
||||
struct timespec raw, cooked;
|
||||
struct timeval raw, cooked;
|
||||
double old_freq_ppm;
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
@@ -597,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;
|
||||
|
||||
old_freq_ppm = current_freq_ppm;
|
||||
|
||||
/* Work out new absolute frequency. Note that absolute frequencies
|
||||
@@ -607,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 */
|
||||
@@ -643,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;
|
||||
@@ -652,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);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -666,40 +571,28 @@ 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))
|
||||
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;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,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);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
38
local.h
38
local.h
@@ -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,
|
||||
@@ -158,17 +159,13 @@ extern void LCL_AccumulateOffset(double offset, double corr_rate);
|
||||
the system clock is fast on true time, i.e. it needs to be stepped
|
||||
backwards. (Same convention as for AccumulateOffset routine). */
|
||||
|
||||
extern 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 void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
|
||||
@@ -197,15 +194,10 @@ extern void LCL_Finalise(void);
|
||||
to a timezone problem. */
|
||||
extern int LCL_MakeStep(void);
|
||||
|
||||
/* Check if the system driver supports leap seconds, i.e. LCL_SetSystemLeap
|
||||
does something */
|
||||
extern int LCL_CanSystemLeap(void);
|
||||
|
||||
/* Routine to set the system clock to correct itself for a leap second and also
|
||||
set its TAI-UTC offset. If supported, leap second will be inserted at the
|
||||
end of the day if the argument is positive, deleted if negative, and zero
|
||||
resets the setting. */
|
||||
extern void LCL_SetSystemLeap(int leap, int tai_offset);
|
||||
/* Routine to 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
|
||||
@@ -214,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 */
|
||||
|
||||
14
localp.h
14
localp.h
@@ -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 */
|
||||
|
||||
198
logging.c
198
logging.c
@@ -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,25 +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;
|
||||
int log_debug_enabled = 0;
|
||||
|
||||
/* ================================================== */
|
||||
/* Flag indicating we have initialised */
|
||||
static int initialised = 0;
|
||||
|
||||
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;
|
||||
@@ -62,18 +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("");
|
||||
initialised = 1;
|
||||
LOG_OpenFileLog(NULL);
|
||||
|
||||
#ifdef WINNT
|
||||
logfile = fopen("./chronyd.err", "a");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -82,16 +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)
|
||||
fclose(file_log);
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_CycleLogFiles();
|
||||
|
||||
Free(debug_prefix);
|
||||
|
||||
initialised = 0;
|
||||
}
|
||||
|
||||
@@ -99,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) {
|
||||
@@ -121,39 +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);
|
||||
|
||||
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)
|
||||
fprintf(file_log, "%s%s:%d:(%s) ", 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);
|
||||
@@ -164,84 +171,50 @@ 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 (write(parent_fd, buf, strlen(buf) + 1) < 0)
|
||||
; /* Not much we can do here */
|
||||
} else if (system_log && parent_fd == 0) {
|
||||
system_log = 0;
|
||||
log_message(1, severity, buf);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_OpenFileLog(const char *log_file)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if (log_file) {
|
||||
f = UTI_OpenFile(NULL, log_file, NULL, 'A', 0640);
|
||||
} else {
|
||||
f = stderr;
|
||||
}
|
||||
|
||||
/* Enable line buffering */
|
||||
setvbuf(f, NULL, _IOLBF, BUFSIZ);
|
||||
|
||||
if (file_log && file_log != stderr)
|
||||
fclose(file_log);
|
||||
|
||||
file_log = f;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
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_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;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -250,8 +223,6 @@ void
|
||||
LOG_SetParentFd(int fd)
|
||||
{
|
||||
parent_fd = fd;
|
||||
if (file_log == stderr)
|
||||
file_log = NULL;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -269,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;
|
||||
@@ -294,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();
|
||||
@@ -315,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] = '=';
|
||||
@@ -336,6 +302,20 @@ 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)
|
||||
{
|
||||
|
||||
100
logging.h
100
logging.h
@@ -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,33 +109,22 @@ 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Close the pipe to the foreground process so it can exit */
|
||||
@@ -124,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 */
|
||||
|
||||
465
main.c
465
main.c
@@ -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
|
||||
@@ -35,12 +35,8 @@
|
||||
#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"
|
||||
@@ -52,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"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -73,28 +67,12 @@ static REF_Mode ref_mode = REF_ModeNormal;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
do_platform_checks(void)
|
||||
{
|
||||
/* Require at least 32-bit integers, two's complement representation and
|
||||
the usual implementation of conversion of unsigned integers */
|
||||
assert(sizeof (int) >= 4);
|
||||
assert(-1 == ~0);
|
||||
assert((int32_t)4294967295U == (int32_t)-1);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
delete_pidfile(void)
|
||||
{
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
|
||||
if (!pidfile)
|
||||
return;
|
||||
|
||||
if (!UTI_RemoveFile(NULL, pidfile, NULL))
|
||||
;
|
||||
/* Don't care if this fails, there's not a lot we can do */
|
||||
unlink(pidfile);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -104,40 +82,30 @@ MAI_CleanupAndExit(void)
|
||||
{
|
||||
if (!initialised) exit(exit_status);
|
||||
|
||||
SRC_DumpSources();
|
||||
if (CNF_GetDumpOnExit()) {
|
||||
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();
|
||||
RTC_Finalise();
|
||||
CAM_Finalise();
|
||||
NIO_Finalise();
|
||||
SYS_Finalise();
|
||||
|
||||
SCK_Finalise();
|
||||
SCH_Finalise();
|
||||
LCL_Finalise();
|
||||
PRV_Finalise();
|
||||
|
||||
delete_pidfile();
|
||||
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
LOG_Finalise();
|
||||
|
||||
exit(exit_status);
|
||||
@@ -148,16 +116,7 @@ MAI_CleanupAndExit(void)
|
||||
static void
|
||||
signal_cleanup(int x)
|
||||
{
|
||||
SCH_QuitProgram();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
quit_timeout(void *arg)
|
||||
{
|
||||
/* Return with non-zero status if the clock is not synchronised */
|
||||
exit_status = REF_GetOurStratum() >= NTP_MAX_STRATUM;
|
||||
if (!initialised) exit(0);
|
||||
SCH_QuitProgram();
|
||||
}
|
||||
|
||||
@@ -176,7 +135,6 @@ ntp_source_resolving_end(void)
|
||||
SRC_ReloadSources();
|
||||
}
|
||||
|
||||
SRC_RemoveDumpFiles();
|
||||
RTC_StartMeasurements();
|
||||
RCL_StartRefclocks();
|
||||
NSR_StartSources();
|
||||
@@ -250,70 +208,84 @@ 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];
|
||||
@@ -324,8 +296,7 @@ go_daemon(void)
|
||||
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
|
||||
@@ -339,7 +310,7 @@ go_daemon(void)
|
||||
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) {
|
||||
exit(0); /* In the 'parent' */
|
||||
} else {
|
||||
@@ -347,7 +318,7 @@ go_daemon(void)
|
||||
|
||||
/* 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
|
||||
@@ -358,70 +329,10 @@ go_daemon(void)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -430,187 +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;
|
||||
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");
|
||||
|
||||
/* 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();
|
||||
@@ -623,30 +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);
|
||||
if (!user) {
|
||||
user = CNF_GetUser();
|
||||
}
|
||||
if (user && strcmp(user, "root")) {
|
||||
SYS_DropRoot(user);
|
||||
}
|
||||
|
||||
LOG_CreateLogFileDir();
|
||||
|
||||
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;
|
||||
@@ -655,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();
|
||||
|
||||
|
||||
37
make_release
37
make_release
@@ -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
|
||||
|
||||
93
manual.c
93
manual.c
@@ -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;
|
||||
|
||||
3
manual.h
3
manual.h
@@ -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);
|
||||
|
||||
93
memory.c
93
memory.c
@@ -1,93 +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;
|
||||
|
||||
r = realloc(ptr, size);
|
||||
if (!r && size)
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static size_t
|
||||
get_array_size(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t array_size;
|
||||
|
||||
array_size = nmemb * size;
|
||||
|
||||
/* Check for overflow */
|
||||
if (nmemb > 0 && array_size / nmemb != size)
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return array_size;
|
||||
}
|
||||
|
||||
void *
|
||||
Malloc2(size_t nmemb, size_t size)
|
||||
{
|
||||
return Malloc(get_array_size(nmemb, size));
|
||||
}
|
||||
|
||||
void *
|
||||
Realloc2(void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
return Realloc(ptr, get_array_size(nmemb, size));
|
||||
}
|
||||
|
||||
char *
|
||||
Strdup(const char *s)
|
||||
{
|
||||
void *r;
|
||||
|
||||
r = strdup(s);
|
||||
if (!r)
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return r;
|
||||
}
|
||||
18
memory.h
18
memory.h
@@ -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
134
mkdirpp.c
Normal 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
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2020
|
||||
* 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,21 +21,11 @@
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for the NTS-NTP protocol
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTS_NTP_H
|
||||
#define GOT_NTS_NTP_H
|
||||
#ifndef GOT_MKDIRPP_H
|
||||
#define GOT_MKDIRPP_H
|
||||
|
||||
#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
|
||||
|
||||
#define NTP_KOD_NTS_NAK 0x4e54534e
|
||||
|
||||
#define NTS_MIN_UNIQ_ID_LENGTH 32
|
||||
#define NTS_MIN_UNPADDED_NONCE_LENGTH 16
|
||||
#define NTS_MAX_COOKIES 8
|
||||
extern int mkdir_and_parents(const char *path);
|
||||
|
||||
#endif
|
||||
114
nameserv.c
114
nameserv.c
@@ -30,11 +30,7 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
|
||||
#include "nameserv.h"
|
||||
#include "socket.h"
|
||||
#include "util.h"
|
||||
|
||||
/* ================================================== */
|
||||
@@ -48,29 +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;
|
||||
|
||||
max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
|
||||
|
||||
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);
|
||||
|
||||
@@ -82,63 +64,38 @@ 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;
|
||||
}
|
||||
|
||||
for (; i < max_addrs; i++)
|
||||
ip_addrs[i].family = IPADDR_UNSPEC;
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure;
|
||||
return result ? DNS_Success : DNS_Failure;
|
||||
#else
|
||||
struct hostent *host;
|
||||
int i;
|
||||
|
||||
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4)
|
||||
return DNS_Failure;
|
||||
|
||||
max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
|
||||
|
||||
host = gethostbyname(name);
|
||||
|
||||
if (host == NULL) {
|
||||
if (h_errno == TRY_AGAIN)
|
||||
return DNS_TryAgain;
|
||||
} else {
|
||||
if (host->h_addrtype != AF_INET || !host->h_addr_list[0])
|
||||
return DNS_Failure;
|
||||
|
||||
for (i = 0; host->h_addr_list[i] && i < max_addrs; i++) {
|
||||
ip_addrs[i].family = IPADDR_INET4;
|
||||
ip_addrs[i].addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[i]);
|
||||
}
|
||||
|
||||
for (; i < max_addrs; i++)
|
||||
ip_addrs[i].family = IPADDR_UNSPEC;
|
||||
|
||||
addr->family = IPADDR_INET4;
|
||||
addr->addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[0]);
|
||||
return DNS_Success;
|
||||
}
|
||||
|
||||
@@ -158,18 +115,33 @@ DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
|
||||
{
|
||||
char *result = NULL;
|
||||
|
||||
#ifdef FEAT_IPV6
|
||||
#ifdef HAVE_IPV6
|
||||
struct sockaddr_in in4;
|
||||
struct sockaddr_in6 in6;
|
||||
IPSockAddr ip_saddr;
|
||||
socklen_t slen;
|
||||
char hbuf[NI_MAXHOST];
|
||||
|
||||
ip_saddr.ip_addr = *ip_addr;
|
||||
ip_saddr.port = 0;
|
||||
|
||||
slen = SCK_IPSockAddrToSockaddr(&ip_saddr, (struct sockaddr *)&in6, sizeof (in6));
|
||||
if (!getnameinfo((struct sockaddr *)&in6, slen, hbuf, sizeof (hbuf), NULL, 0, 0))
|
||||
result = hbuf;
|
||||
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;
|
||||
@@ -179,7 +151,7 @@ DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
|
||||
addr = htonl(ip_addr->addr.in4);
|
||||
host = gethostbyaddr((const char *) &addr, sizeof (ip_addr), AF_INET);
|
||||
break;
|
||||
#ifdef FEAT_IPV6
|
||||
#ifdef HAVE_IPV6
|
||||
case IPADDR_INET6:
|
||||
host = gethostbyaddr((const void *) ip_addr->addr.in6, sizeof (ip_addr->addr.in6), AF_INET6);
|
||||
break;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
94
ntp.h
94
ntp.h
@@ -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,64 +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)
|
||||
|
||||
/* 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;
|
||||
typedef union {
|
||||
NTP_Packet ntp_pkt;
|
||||
uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
|
||||
} ReceiveBuffer;
|
||||
|
||||
/* Structure describing an NTP packet */
|
||||
typedef struct {
|
||||
int length;
|
||||
int version;
|
||||
NTP_Mode mode;
|
||||
|
||||
int ext_fields;
|
||||
|
||||
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;
|
||||
int stratum;
|
||||
} NTP_Sample;
|
||||
#define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
|
||||
|
||||
#endif /* GOT_NTP_H */
|
||||
|
||||
494
ntp_auth.c
494
ntp_auth.c
@@ -1,494 +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_ext.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 int
|
||||
is_zero_data(unsigned char *data, int length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
if (data[i] != 0)
|
||||
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, const IPSockAddr *ntp_address)
|
||||
{
|
||||
NAU_Instance instance = create_instance(NTP_AUTH_NTS);
|
||||
|
||||
instance->nts = NNC_CreateInstance(nts_address, name, ntp_address);
|
||||
|
||||
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_ParsePacket(NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
{
|
||||
int parsed, remainder, ef_length, ef_type;
|
||||
unsigned char *data;
|
||||
|
||||
data = (void *)packet;
|
||||
parsed = NTP_HEADER_LENGTH;
|
||||
remainder = info->length - parsed;
|
||||
|
||||
info->ext_fields = 0;
|
||||
|
||||
/* Check if this is a plain NTP packet with no extension fields or MAC */
|
||||
if (remainder <= 0)
|
||||
return 1;
|
||||
|
||||
assert(remainder % 4 == 0);
|
||||
|
||||
/* In NTPv3 and older packets don't have extension fields. Anything after
|
||||
the header is assumed to be a MAC. */
|
||||
if (info->version <= 3) {
|
||||
info->auth.mode = NTP_AUTH_SYMMETRIC;
|
||||
info->auth.mac.start = parsed;
|
||||
info->auth.mac.length = remainder;
|
||||
info->auth.mac.key_id = ntohl(*(uint32_t *)(data + parsed));
|
||||
|
||||
/* Check if it is an MS-SNTP authenticator field or extended authenticator
|
||||
field with zeroes as digest */
|
||||
if (info->version == 3 && info->auth.mac.key_id != 0) {
|
||||
if (remainder == 20 && is_zero_data(data + parsed + 4, remainder - 4))
|
||||
info->auth.mode = NTP_AUTH_MSSNTP;
|
||||
else if (remainder == 72 && is_zero_data(data + parsed + 8, remainder - 8))
|
||||
info->auth.mode = NTP_AUTH_MSSNTP_EXT;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for a crypto NAK */
|
||||
if (remainder == 4 && ntohl(*(uint32_t *)(data + parsed)) == 0) {
|
||||
info->auth.mode = NTP_AUTH_SYMMETRIC;
|
||||
info->auth.mac.start = parsed;
|
||||
info->auth.mac.length = remainder;
|
||||
info->auth.mac.key_id = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse the rest of the NTPv4 packet */
|
||||
|
||||
while (remainder > 0) {
|
||||
/* Check if the remaining data is a MAC */
|
||||
if (remainder >= NTP_MIN_MAC_LENGTH && remainder <= NTP_MAX_V4_MAC_LENGTH)
|
||||
break;
|
||||
|
||||
/* Check if this is a valid NTPv4 extension field and skip it */
|
||||
if (!NEF_ParseField(packet, info->length, parsed, &ef_length, &ef_type, NULL, NULL)) {
|
||||
DEBUG_LOG("Invalid format");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(ef_length > 0 && ef_length % 4 == 0);
|
||||
|
||||
switch (ef_type) {
|
||||
case NTP_EF_NTS_UNIQUE_IDENTIFIER:
|
||||
case NTP_EF_NTS_COOKIE:
|
||||
case NTP_EF_NTS_COOKIE_PLACEHOLDER:
|
||||
case NTP_EF_NTS_AUTH_AND_EEF:
|
||||
info->auth.mode = NTP_AUTH_NTS;
|
||||
break;
|
||||
default:
|
||||
DEBUG_LOG("Unknown extension field type=%x", (unsigned int)ef_type);
|
||||
}
|
||||
|
||||
info->ext_fields++;
|
||||
parsed += ef_length;
|
||||
remainder = info->length - parsed;
|
||||
}
|
||||
|
||||
if (remainder == 0) {
|
||||
/* No MAC */
|
||||
return 1;
|
||||
} else if (remainder >= NTP_MIN_MAC_LENGTH) {
|
||||
info->auth.mode = NTP_AUTH_SYMMETRIC;
|
||||
info->auth.mac.start = parsed;
|
||||
info->auth.mac.length = remainder;
|
||||
info->auth.mac.key_id = ntohl(*(uint32_t *)(data + parsed));
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Invalid format");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
87
ntp_auth.h
87
ntp_auth.h
@@ -1,87 +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,
|
||||
const IPSockAddr *ntp_address);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Parse a request or response to detect the authentication mode */
|
||||
extern int NAU_ParsePacket(NTP_Packet *packet, 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
|
||||
2528
ntp_core.c
2528
ntp_core.c
File diff suppressed because it is too large
Load Diff
59
ntp_core.h
59
ntp_core.h
@@ -38,18 +38,6 @@ typedef enum {
|
||||
NTP_SERVER, NTP_PEER
|
||||
} NTP_Source_Type;
|
||||
|
||||
typedef enum {
|
||||
NTP_TS_DAEMON = 0,
|
||||
NTP_TS_KERNEL,
|
||||
NTP_TS_HARDWARE
|
||||
} NTP_Timestamp_Source;
|
||||
|
||||
typedef struct {
|
||||
struct timespec ts;
|
||||
double err;
|
||||
NTP_Timestamp_Source source;
|
||||
} NTP_Local_Timestamp;
|
||||
|
||||
/* This is a private data type used for storing the instance record for
|
||||
each source that we are chiming with */
|
||||
typedef struct NCR_Instance_Record *NCR_Instance;
|
||||
@@ -59,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);
|
||||
@@ -71,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);
|
||||
|
||||
@@ -121,9 +92,7 @@ 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);
|
||||
@@ -133,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
192
ntp_ext.c
@@ -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;
|
||||
}
|
||||
43
ntp_ext.h
43
ntp_ext.h
@@ -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
|
||||
738
ntp_io.c
738
ntp_io.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Timo Teras 2009
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2013-2016, 2018-2020
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2013-2014
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -34,103 +34,186 @@
|
||||
#include "ntp_core.h"
|
||||
#include "ntp_sources.h"
|
||||
#include "sched.h"
|
||||
#include "socket.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "conf.h"
|
||||
#include "privops.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
#include "ntp_io_linux.h"
|
||||
#endif
|
||||
|
||||
#define INVALID_SOCK_FD -1
|
||||
|
||||
union sockaddr_in46 {
|
||||
struct sockaddr_in in4;
|
||||
#ifdef HAVE_IPV6
|
||||
struct sockaddr_in6 in6;
|
||||
#endif
|
||||
struct sockaddr u;
|
||||
};
|
||||
|
||||
/* The server/peer and client sockets for IPv4 and IPv6 */
|
||||
static int server_sock_fd4;
|
||||
static int server_sock_fd6;
|
||||
static int client_sock_fd4;
|
||||
#ifdef HAVE_IPV6
|
||||
static int server_sock_fd6;
|
||||
static int client_sock_fd6;
|
||||
|
||||
/* Reference counters for server sockets to keep them open only when needed */
|
||||
static int server_sock_ref4;
|
||||
static int server_sock_ref6;
|
||||
#endif
|
||||
|
||||
/* Flag indicating we create a new connected client socket for each
|
||||
server instead of sharing client_sock_fd4 and client_sock_fd6 */
|
||||
static int separate_client_sockets;
|
||||
|
||||
/* Flag indicating the server sockets are not created dynamically when needed,
|
||||
either to have a socket for client requests when separate client sockets
|
||||
are disabled and client port is equal to server port, or the server port is
|
||||
disabled */
|
||||
static int permanent_server_sockets;
|
||||
|
||||
/* Flag indicating the server IPv4 socket is bound to an address */
|
||||
static int bound_server_sock_fd4;
|
||||
|
||||
/* Flag indicating that we have been initialised */
|
||||
static int initialised=0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Forward prototypes */
|
||||
static void read_from_socket(int sock_fd, int event, void *anything);
|
||||
static void read_from_socket(void *anything);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_socket(int family, int local_port, int client_only, IPSockAddr *remote_addr)
|
||||
prepare_socket(int family, int port_number, int client_only)
|
||||
{
|
||||
int sock_fd, sock_flags, dscp, events = SCH_FILE_INPUT;
|
||||
IPSockAddr local_addr;
|
||||
char *iface;
|
||||
union sockaddr_in46 my_addr;
|
||||
socklen_t my_addr_len;
|
||||
int sock_fd;
|
||||
IPAddr bind_address;
|
||||
int on_off = 1;
|
||||
|
||||
/* Open Internet domain UDP socket for NTP message transmissions */
|
||||
|
||||
if (!SCK_IsIpFamilyEnabled(family))
|
||||
return INVALID_SOCK_FD;
|
||||
sock_fd = socket(family, SOCK_DGRAM, 0);
|
||||
|
||||
if (!client_only) {
|
||||
CNF_GetBindAddress(family, &local_addr.ip_addr);
|
||||
iface = CNF_GetBindNtpInterface();
|
||||
} else {
|
||||
CNF_GetBindAcquisitionAddress(family, &local_addr.ip_addr);
|
||||
iface = CNF_GetBindAcquisitionInterface();
|
||||
}
|
||||
|
||||
local_addr.port = local_port;
|
||||
|
||||
sock_flags = SCK_FLAG_RX_DEST_ADDR | SCK_FLAG_PRIV_BIND;
|
||||
if (!client_only)
|
||||
sock_flags |= SCK_FLAG_BROADCAST;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(remote_addr, &local_addr, iface, sock_flags);
|
||||
if (sock_fd < 0) {
|
||||
if (!client_only)
|
||||
LOG(LOGS_ERR, "Could not open NTP socket on %s", UTI_IPSockAddrToString(&local_addr));
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
|
||||
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
dscp = CNF_GetNtpDscp();
|
||||
if (dscp > 0 && dscp < 64) {
|
||||
#ifdef IP_TOS
|
||||
if (!SCK_SetIntOption(sock_fd, IPPROTO_IP, IP_TOS, dscp << 2))
|
||||
;
|
||||
/* Close on exec */
|
||||
UTI_FdSetCloexec(sock_fd);
|
||||
|
||||
/* Prepare local address */
|
||||
memset(&my_addr, 0, sizeof (my_addr));
|
||||
my_addr_len = 0;
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
if (!client_only)
|
||||
CNF_GetBindAddress(IPADDR_INET4, &bind_address);
|
||||
else
|
||||
CNF_GetBindAcquisitionAddress(IPADDR_INET4, &bind_address);
|
||||
|
||||
if (bind_address.family == IPADDR_INET4)
|
||||
my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4);
|
||||
else if (port_number)
|
||||
my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
else
|
||||
break;
|
||||
|
||||
my_addr.in4.sin_family = family;
|
||||
my_addr.in4.sin_port = htons(port_number);
|
||||
my_addr_len = sizeof (my_addr.in4);
|
||||
|
||||
break;
|
||||
#ifdef HAVE_IPV6
|
||||
case AF_INET6:
|
||||
if (!client_only)
|
||||
CNF_GetBindAddress(IPADDR_INET6, &bind_address);
|
||||
else
|
||||
CNF_GetBindAcquisitionAddress(IPADDR_INET6, &bind_address);
|
||||
|
||||
if (bind_address.family == IPADDR_INET6)
|
||||
memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6,
|
||||
sizeof (my_addr.in6.sin6_addr.s6_addr));
|
||||
else if (port_number)
|
||||
my_addr.in6.sin6_addr = in6addr_any;
|
||||
else
|
||||
break;
|
||||
|
||||
my_addr.in6.sin6_family = family;
|
||||
my_addr.in6.sin6_port = htons(port_number);
|
||||
my_addr_len = sizeof (my_addr.in6);
|
||||
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (!client_only && family == IPADDR_INET4 && local_addr.port > 0)
|
||||
bound_server_sock_fd4 = local_addr.ip_addr.addr.in4 != INADDR_ANY;
|
||||
/* Make the socket capable of re-using an old address if binding to a specific port */
|
||||
if (port_number &&
|
||||
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set reuseaddr socket options");
|
||||
/* Don't quit - we might survive anyway */
|
||||
}
|
||||
|
||||
/* Make the socket capable of sending broadcast pkts - needed for NTP broadcast mode */
|
||||
if (!client_only &&
|
||||
setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set broadcast socket options");
|
||||
/* Don't quit - we might survive anyway */
|
||||
}
|
||||
|
||||
/* Enable kernel/HW timestamping of packets */
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, client_only, &events))
|
||||
#ifdef SO_TIMESTAMP
|
||||
/* Enable receiving of timestamp control messages */
|
||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMP, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set timestamp socket options");
|
||||
/* Don't quit - we might survive anyway */
|
||||
}
|
||||
#endif
|
||||
if (!SCK_EnableKernelRxTimestamping(sock_fd))
|
||||
;
|
||||
|
||||
/* Register handler for read and possibly exception events on the socket */
|
||||
SCH_AddFileHandler(sock_fd, events, read_from_socket, NULL);
|
||||
#ifdef IP_FREEBIND
|
||||
/* Allow binding to address that doesn't exist yet */
|
||||
if (my_addr_len > 0 &&
|
||||
setsockopt(sock_fd, IPPROTO_IP, IP_FREEBIND, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set free bind socket option");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (family == AF_INET) {
|
||||
#ifdef IP_PKTINFO
|
||||
/* We want the local IP info on server sockets */
|
||||
if (!client_only &&
|
||||
setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set packet info socket option");
|
||||
/* Don't quit - we might survive anyway */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (family == AF_INET6) {
|
||||
#ifdef IPV6_V6ONLY
|
||||
/* Receive IPv6 packets only */
|
||||
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPV6_V6ONLY socket option");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!client_only) {
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPv6 packet info socket option");
|
||||
}
|
||||
#elif defined(IPV6_PKTINFO)
|
||||
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPv6 packet info socket option");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Bind the socket if a port or address was specified */
|
||||
if (my_addr_len > 0 && bind(sock_fd, &my_addr.u, my_addr_len) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not bind %s NTP socket : %s",
|
||||
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
|
||||
close(sock_fd);
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
/* Register handler for read events on the socket */
|
||||
SCH_AddInputFileHandler(sock_fd, read_from_socket, (void *)(long)sock_fd);
|
||||
|
||||
return sock_fd;
|
||||
}
|
||||
@@ -138,9 +221,58 @@ open_socket(int family, int local_port, int client_only, IPSockAddr *remote_addr
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_separate_client_socket(IPSockAddr *remote_addr)
|
||||
prepare_separate_client_socket(int family)
|
||||
{
|
||||
return open_socket(remote_addr->ip_addr.family, 0, 1, remote_addr);
|
||||
switch (family) {
|
||||
case IPADDR_INET4:
|
||||
return prepare_socket(AF_INET, 0, 1);
|
||||
#ifdef HAVE_IPV6
|
||||
case IPADDR_INET6:
|
||||
return prepare_socket(AF_INET6, 0, 1);
|
||||
#endif
|
||||
default:
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
connect_socket(int sock_fd, NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
union sockaddr_in46 addr;
|
||||
socklen_t addr_len;
|
||||
|
||||
memset(&addr, 0, sizeof (addr));
|
||||
|
||||
switch (remote_addr->ip_addr.family) {
|
||||
case IPADDR_INET4:
|
||||
addr_len = sizeof (addr.in4);
|
||||
addr.in4.sin_family = AF_INET;
|
||||
addr.in4.sin_addr.s_addr = htonl(remote_addr->ip_addr.addr.in4);
|
||||
addr.in4.sin_port = htons(remote_addr->port);
|
||||
break;
|
||||
#ifdef HAVE_IPV6
|
||||
case IPADDR_INET6:
|
||||
addr_len = sizeof (addr.in6);
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
memcpy(addr.in6.sin6_addr.s6_addr, remote_addr->ip_addr.addr.in6,
|
||||
sizeof (addr.in6.sin6_addr.s6_addr));
|
||||
addr.in6.sin6_port = htons(remote_addr->port);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (connect(sock_fd, &addr.u, addr_len) < 0) {
|
||||
DEBUG_LOG(LOGF_NtpIO, "Could not connect NTP socket to %s:%d : %s",
|
||||
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -151,37 +283,19 @@ close_socket(int sock_fd)
|
||||
if (sock_fd == INVALID_SOCK_FD)
|
||||
return;
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
NIO_Linux_NotifySocketClosing(sock_fd);
|
||||
#endif
|
||||
SCH_RemoveFileHandler(sock_fd);
|
||||
SCK_CloseSocket(sock_fd);
|
||||
SCH_RemoveInputFileHandler(sock_fd);
|
||||
close(sock_fd);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Initialise(void)
|
||||
NIO_Initialise(int family)
|
||||
{
|
||||
int server_port, client_port;
|
||||
|
||||
assert(!initialised);
|
||||
initialised = 1;
|
||||
|
||||
#ifdef PRIVOPS_BINDSOCKET
|
||||
SCK_SetPrivBind(PRV_BindSocket);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
NIO_Linux_Initialise();
|
||||
#else
|
||||
if (1) {
|
||||
CNF_HwTsInterface *conf_iface;
|
||||
if (CNF_GetHwTsInterface(0, &conf_iface))
|
||||
LOG_FATAL("HW timestamping not supported");
|
||||
}
|
||||
#endif
|
||||
|
||||
server_port = CNF_GetNTPPort();
|
||||
client_port = CNF_GetAcquisitionPort();
|
||||
|
||||
@@ -190,36 +304,46 @@ NIO_Initialise(void)
|
||||
if (client_port < 0)
|
||||
client_port = 0;
|
||||
|
||||
permanent_server_sockets = !server_port || (!separate_client_sockets &&
|
||||
client_port == server_port);
|
||||
|
||||
server_sock_fd4 = INVALID_SOCK_FD;
|
||||
server_sock_fd6 = INVALID_SOCK_FD;
|
||||
client_sock_fd4 = INVALID_SOCK_FD;
|
||||
#ifdef HAVE_IPV6
|
||||
server_sock_fd6 = INVALID_SOCK_FD;
|
||||
client_sock_fd6 = INVALID_SOCK_FD;
|
||||
server_sock_ref4 = 0;
|
||||
server_sock_ref6 = 0;
|
||||
#endif
|
||||
|
||||
if (permanent_server_sockets && server_port) {
|
||||
server_sock_fd4 = open_socket(IPADDR_INET4, server_port, 0, NULL);
|
||||
server_sock_fd6 = open_socket(IPADDR_INET6, server_port, 0, NULL);
|
||||
}
|
||||
|
||||
if (!separate_client_sockets) {
|
||||
if (client_port != server_port || !server_port) {
|
||||
client_sock_fd4 = open_socket(IPADDR_INET4, client_port, 1, NULL);
|
||||
client_sock_fd6 = open_socket(IPADDR_INET6, client_port, 1, NULL);
|
||||
} else {
|
||||
client_sock_fd4 = server_sock_fd4;
|
||||
client_sock_fd6 = server_sock_fd6;
|
||||
if (family == IPADDR_UNSPEC || family == IPADDR_INET4) {
|
||||
if (server_port)
|
||||
server_sock_fd4 = prepare_socket(AF_INET, server_port, 0);
|
||||
if (!separate_client_sockets) {
|
||||
if (client_port != server_port || !server_port)
|
||||
client_sock_fd4 = prepare_socket(AF_INET, client_port, 1);
|
||||
else
|
||||
client_sock_fd4 = server_sock_fd4;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
if (family == IPADDR_UNSPEC || family == IPADDR_INET6) {
|
||||
if (server_port)
|
||||
server_sock_fd6 = prepare_socket(AF_INET6, server_port, 0);
|
||||
if (!separate_client_sockets) {
|
||||
if (client_port != server_port || !server_port)
|
||||
client_sock_fd6 = prepare_socket(AF_INET6, client_port, 1);
|
||||
else
|
||||
client_sock_fd6 = server_sock_fd6;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((server_port && permanent_server_sockets &&
|
||||
server_sock_fd4 == INVALID_SOCK_FD && server_sock_fd6 == INVALID_SOCK_FD) ||
|
||||
(!separate_client_sockets &&
|
||||
client_sock_fd4 == INVALID_SOCK_FD && client_sock_fd6 == INVALID_SOCK_FD)) {
|
||||
LOG_FATAL("Could not open NTP sockets");
|
||||
if ((server_port && server_sock_fd4 == INVALID_SOCK_FD
|
||||
#ifdef HAVE_IPV6
|
||||
&& server_sock_fd6 == INVALID_SOCK_FD
|
||||
#endif
|
||||
) || (!separate_client_sockets && client_sock_fd4 == INVALID_SOCK_FD
|
||||
#ifdef HAVE_IPV6
|
||||
&& client_sock_fd6 == INVALID_SOCK_FD
|
||||
#endif
|
||||
)) {
|
||||
LOG_FATAL(LOGF_NtpIO, "Could not open NTP sockets");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,32 +356,40 @@ NIO_Finalise(void)
|
||||
close_socket(client_sock_fd4);
|
||||
close_socket(server_sock_fd4);
|
||||
server_sock_fd4 = client_sock_fd4 = INVALID_SOCK_FD;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (server_sock_fd6 != client_sock_fd6)
|
||||
close_socket(client_sock_fd6);
|
||||
close_socket(server_sock_fd6);
|
||||
server_sock_fd6 = client_sock_fd6 = INVALID_SOCK_FD;
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
NIO_Linux_Finalise();
|
||||
#endif
|
||||
|
||||
initialised = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
|
||||
NIO_GetClientSocket(NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
if (separate_client_sockets) {
|
||||
return open_separate_client_socket(remote_addr);
|
||||
int sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family);
|
||||
|
||||
if (sock_fd == INVALID_SOCK_FD)
|
||||
return INVALID_SOCK_FD;
|
||||
|
||||
if (!connect_socket(sock_fd, remote_addr)) {
|
||||
close_socket(sock_fd);
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
return sock_fd;
|
||||
} else {
|
||||
switch (remote_addr->ip_addr.family) {
|
||||
case IPADDR_INET4:
|
||||
return client_sock_fd4;
|
||||
#ifdef HAVE_IPV6
|
||||
case IPADDR_INET6:
|
||||
return client_sock_fd6;
|
||||
#endif
|
||||
default:
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
@@ -267,25 +399,15 @@ NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_OpenServerSocket(NTP_Remote_Address *remote_addr)
|
||||
NIO_GetServerSocket(NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
switch (remote_addr->ip_addr.family) {
|
||||
case IPADDR_INET4:
|
||||
if (permanent_server_sockets)
|
||||
return server_sock_fd4;
|
||||
if (server_sock_fd4 == INVALID_SOCK_FD)
|
||||
server_sock_fd4 = open_socket(IPADDR_INET4, CNF_GetNTPPort(), 0, NULL);
|
||||
if (server_sock_fd4 != INVALID_SOCK_FD)
|
||||
server_sock_ref4++;
|
||||
return server_sock_fd4;
|
||||
#ifdef HAVE_IPV6
|
||||
case IPADDR_INET6:
|
||||
if (permanent_server_sockets)
|
||||
return server_sock_fd6;
|
||||
if (server_sock_fd6 == INVALID_SOCK_FD)
|
||||
server_sock_fd6 = open_socket(IPADDR_INET6, CNF_GetNTPPort(), 0, NULL);
|
||||
if (server_sock_fd6 != INVALID_SOCK_FD)
|
||||
server_sock_ref6++;
|
||||
return server_sock_fd6;
|
||||
#endif
|
||||
default:
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
@@ -302,182 +424,276 @@ NIO_CloseClientSocket(int sock_fd)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_CloseServerSocket(int sock_fd)
|
||||
{
|
||||
if (permanent_server_sockets || sock_fd == INVALID_SOCK_FD)
|
||||
return;
|
||||
|
||||
if (sock_fd == server_sock_fd4) {
|
||||
if (--server_sock_ref4 <= 0) {
|
||||
close_socket(server_sock_fd4);
|
||||
server_sock_fd4 = INVALID_SOCK_FD;
|
||||
}
|
||||
} else if (sock_fd == server_sock_fd6) {
|
||||
if (--server_sock_ref6 <= 0) {
|
||||
close_socket(server_sock_fd6);
|
||||
server_sock_fd6 = INVALID_SOCK_FD;
|
||||
}
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_IsServerSocket(int sock_fd)
|
||||
{
|
||||
return sock_fd != INVALID_SOCK_FD &&
|
||||
(sock_fd == server_sock_fd4 || sock_fd == server_sock_fd6);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_IsServerSocketOpen(void)
|
||||
{
|
||||
return server_sock_fd4 != INVALID_SOCK_FD || server_sock_fd6 != INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_IsServerConnectable(NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
int sock_fd;
|
||||
|
||||
sock_fd = open_separate_client_socket(remote_addr);
|
||||
if (sock_fd == INVALID_SOCK_FD)
|
||||
return 0;
|
||||
|
||||
close_socket(sock_fd);
|
||||
|
||||
return 1;
|
||||
(sock_fd == server_sock_fd4
|
||||
#ifdef HAVE_IPV6
|
||||
|| sock_fd == server_sock_fd6
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
process_message(SCK_Message *message, int sock_fd, int event)
|
||||
read_from_socket(void *anything)
|
||||
{
|
||||
/* This should only be called when there is something
|
||||
to read, otherwise it will block. */
|
||||
|
||||
int status, sock_fd;
|
||||
ReceiveBuffer message;
|
||||
union sockaddr_in46 where_from;
|
||||
unsigned int flags = 0;
|
||||
struct timeval now;
|
||||
double now_err;
|
||||
NTP_Remote_Address remote_addr;
|
||||
NTP_Local_Address local_addr;
|
||||
NTP_Local_Timestamp local_ts;
|
||||
struct timespec sched_ts;
|
||||
char cmsgbuf[256];
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
|
||||
local_ts.source = NTP_TS_DAEMON;
|
||||
sched_ts = local_ts.ts;
|
||||
assert(initialised);
|
||||
|
||||
if (message->addr_type != SCK_ADDR_IP) {
|
||||
DEBUG_LOG("Unexpected address type");
|
||||
return;
|
||||
}
|
||||
SCH_GetLastEventTime(&now, &now_err, NULL);
|
||||
|
||||
local_addr.ip_addr = message->local_addr.ip;
|
||||
local_addr.if_index = message->if_index;;
|
||||
local_addr.sock_fd = sock_fd;
|
||||
iov.iov_base = message.arbitrary;
|
||||
iov.iov_len = sizeof(message);
|
||||
msg.msg_name = &where_from;
|
||||
msg.msg_namelen = sizeof(where_from);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = (void *) cmsgbuf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
if (NIO_Linux_ProcessMessage(message, &local_addr, &local_ts, event))
|
||||
return;
|
||||
#else
|
||||
if (!UTI_IsZeroTimespec(&message->timestamp.kernel)) {
|
||||
LCL_CookTime(&message->timestamp.kernel, &local_ts.ts, &local_ts.err);
|
||||
local_ts.source = NTP_TS_KERNEL;
|
||||
}
|
||||
sock_fd = (long)anything;
|
||||
status = recvmsg(sock_fd, &msg, flags);
|
||||
|
||||
/* Don't bother checking if read failed or why if it did. More
|
||||
likely than not, it will be connection refused, resulting from a
|
||||
previous sendto() directing a datagram at a port that is not
|
||||
listening (which appears to generate an ICMP response, and on
|
||||
some architectures e.g. Linux this is translated into an error
|
||||
reponse on a subsequent recvfrom). */
|
||||
|
||||
if (status > 0) {
|
||||
if (msg.msg_namelen > sizeof (where_from))
|
||||
LOG_FATAL(LOGF_NtpIO, "Truncated source address");
|
||||
|
||||
switch (where_from.u.sa_family) {
|
||||
case AF_INET:
|
||||
remote_addr.ip_addr.family = IPADDR_INET4;
|
||||
remote_addr.ip_addr.addr.in4 = ntohl(where_from.in4.sin_addr.s_addr);
|
||||
remote_addr.port = ntohs(where_from.in4.sin_port);
|
||||
break;
|
||||
#ifdef HAVE_IPV6
|
||||
case AF_INET6:
|
||||
remote_addr.ip_addr.family = IPADDR_INET6;
|
||||
memcpy(&remote_addr.ip_addr.addr.in6, where_from.in6.sin6_addr.s6_addr,
|
||||
sizeof (remote_addr.ip_addr.addr.in6));
|
||||
remote_addr.port = ntohs(where_from.in6.sin6_port);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
local_addr.sock_fd = sock_fd;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
#ifdef IP_PKTINFO
|
||||
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
|
||||
struct in_pktinfo ipi;
|
||||
|
||||
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
|
||||
local_addr.ip_addr.addr.in4 = ntohl(ipi.ipi_spec_dst.s_addr);
|
||||
local_addr.ip_addr.family = IPADDR_INET4;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (local_ts.source != NTP_TS_DAEMON)
|
||||
DEBUG_LOG("Updated RX timestamp delay=%.9f tss=%u",
|
||||
UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts), local_ts.source);
|
||||
#if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
|
||||
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
|
||||
struct in6_pktinfo ipi;
|
||||
|
||||
/* Just ignore the packet if it's not of a recognized length */
|
||||
if (message->length < NTP_HEADER_LENGTH || message->length > sizeof (NTP_Packet)) {
|
||||
DEBUG_LOG("Unexpected length");
|
||||
return;
|
||||
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
|
||||
memcpy(&local_addr.ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
|
||||
sizeof (local_addr.ip_addr.addr.in6));
|
||||
local_addr.ip_addr.family = IPADDR_INET6;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SO_TIMESTAMP
|
||||
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP) {
|
||||
struct timeval tv;
|
||||
|
||||
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
|
||||
LCL_CookTime(&tv, &now, &now_err);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (status > 0) {
|
||||
DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd %d",
|
||||
status,
|
||||
UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
|
||||
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd);
|
||||
}
|
||||
|
||||
if (status >= NTP_NORMAL_PACKET_SIZE && status <= sizeof(NTP_Packet)) {
|
||||
|
||||
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err,
|
||||
&remote_addr, &local_addr, status);
|
||||
|
||||
} else {
|
||||
|
||||
/* Just ignore the packet if it's not of a recognized length */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
NSR_ProcessRx(&message->remote_addr.ip, &local_addr, &local_ts, message->data, message->length);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Send a packet to given address */
|
||||
|
||||
static void
|
||||
read_from_socket(int sock_fd, int event, void *anything)
|
||||
static int
|
||||
send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
|
||||
{
|
||||
SCK_Message *messages;
|
||||
int i, received, flags = 0;
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
if (NIO_Linux_ProcessEvent(sock_fd, event))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (event == SCH_FILE_EXCEPTION) {
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
flags |= SCK_FLAG_MSG_ERRQUEUE;
|
||||
#else
|
||||
assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
messages = SCK_ReceiveMessages(sock_fd, flags, &received);
|
||||
if (!messages)
|
||||
return;
|
||||
|
||||
for (i = 0; i < received; i++)
|
||||
process_message(&messages[i], sock_fd, event);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Send a packet to remote address from local address */
|
||||
|
||||
int
|
||||
NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
|
||||
NTP_Local_Address *local_addr, int length, int process_tx)
|
||||
{
|
||||
SCK_Message message;
|
||||
union sockaddr_in46 remote;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
char cmsgbuf[256];
|
||||
int cmsglen;
|
||||
socklen_t addrlen = 0;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
if (local_addr->sock_fd == INVALID_SOCK_FD) {
|
||||
DEBUG_LOG("No socket to send to %s", UTI_IPSockAddrToString(remote_addr));
|
||||
DEBUG_LOG(LOGF_NtpIO, "No socket to send to %s:%d",
|
||||
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SCK_InitMessage(&message, SCK_ADDR_IP);
|
||||
|
||||
message.data = packet;
|
||||
message.length = length;
|
||||
|
||||
/* Specify remote address if the socket is not connected */
|
||||
if (NIO_IsServerSocket(local_addr->sock_fd) || !separate_client_sockets) {
|
||||
message.remote_addr.ip.ip_addr = remote_addr->ip_addr;
|
||||
message.remote_addr.ip.port = remote_addr->port;
|
||||
switch (remote_addr->ip_addr.family) {
|
||||
case IPADDR_INET4:
|
||||
/* Don't set address with connected socket */
|
||||
if (local_addr->sock_fd != server_sock_fd4 && separate_client_sockets)
|
||||
break;
|
||||
memset(&remote.in4, 0, sizeof (remote.in4));
|
||||
addrlen = sizeof (remote.in4);
|
||||
remote.in4.sin_family = AF_INET;
|
||||
remote.in4.sin_port = htons(remote_addr->port);
|
||||
remote.in4.sin_addr.s_addr = htonl(remote_addr->ip_addr.addr.in4);
|
||||
break;
|
||||
#ifdef HAVE_IPV6
|
||||
case IPADDR_INET6:
|
||||
/* Don't set address with connected socket */
|
||||
if (local_addr->sock_fd != server_sock_fd6 && separate_client_sockets)
|
||||
break;
|
||||
memset(&remote.in6, 0, sizeof (remote.in6));
|
||||
addrlen = sizeof (remote.in6);
|
||||
remote.in6.sin6_family = AF_INET6;
|
||||
remote.in6.sin6_port = htons(remote_addr->port);
|
||||
memcpy(&remote.in6.sin6_addr.s6_addr, &remote_addr->ip_addr.addr.in6,
|
||||
sizeof (remote.in6.sin6_addr.s6_addr));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
message.local_addr.ip = local_addr->ip_addr;
|
||||
if (addrlen) {
|
||||
msg.msg_name = &remote.u;
|
||||
msg.msg_namelen = addrlen;
|
||||
} else {
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
}
|
||||
|
||||
/* Don't require responses to non-link-local addresses to use the same
|
||||
interface */
|
||||
message.if_index = SCK_IsLinkLocalIPAddress(&message.remote_addr.ip.ip_addr) ?
|
||||
local_addr->if_index : INVALID_IF_INDEX;
|
||||
iov.iov_base = packet;
|
||||
iov.iov_len = packetlen;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = cmsgbuf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf);
|
||||
msg.msg_flags = 0;
|
||||
cmsglen = 0;
|
||||
|
||||
#if !defined(HAVE_IN_PKTINFO) && defined(IP_SENDSRCADDR)
|
||||
/* On FreeBSD a local IPv4 address cannot be specified on bound socket */
|
||||
if (message.local_addr.ip.family == IPADDR_INET4 &&
|
||||
(local_addr->sock_fd != server_sock_fd4 || bound_server_sock_fd4))
|
||||
message.local_addr.ip.family = IPADDR_UNSPEC;
|
||||
#ifdef IP_PKTINFO
|
||||
if (local_addr->ip_addr.family == IPADDR_INET4) {
|
||||
struct cmsghdr *cmsg;
|
||||
struct in_pktinfo *ipi;
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
memset(cmsg, 0, CMSG_SPACE(sizeof(struct in_pktinfo)));
|
||||
cmsglen += CMSG_SPACE(sizeof(struct in_pktinfo));
|
||||
|
||||
cmsg->cmsg_level = IPPROTO_IP;
|
||||
cmsg->cmsg_type = IP_PKTINFO;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
|
||||
ipi = (struct in_pktinfo *) CMSG_DATA(cmsg);
|
||||
ipi->ipi_spec_dst.s_addr = htonl(local_addr->ip_addr.addr.in4);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
if (process_tx)
|
||||
NIO_Linux_RequestTxTimestamp(&message, local_addr->sock_fd);
|
||||
#if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
|
||||
if (local_addr->ip_addr.family == IPADDR_INET6) {
|
||||
struct cmsghdr *cmsg;
|
||||
struct in6_pktinfo *ipi;
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
memset(cmsg, 0, CMSG_SPACE(sizeof(struct in6_pktinfo)));
|
||||
cmsglen += CMSG_SPACE(sizeof(struct in6_pktinfo));
|
||||
|
||||
cmsg->cmsg_level = IPPROTO_IPV6;
|
||||
cmsg->cmsg_type = IPV6_PKTINFO;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||
|
||||
ipi = (struct in6_pktinfo *) CMSG_DATA(cmsg);
|
||||
memcpy(&ipi->ipi6_addr.s6_addr, &local_addr->ip_addr.addr.in6,
|
||||
sizeof(ipi->ipi6_addr.s6_addr));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!SCK_SendMessage(local_addr->sock_fd, &message, 0))
|
||||
msg.msg_controllen = cmsglen;
|
||||
/* This is apparently required on some systems */
|
||||
if (!cmsglen)
|
||||
msg.msg_control = NULL;
|
||||
|
||||
if (sendmsg(local_addr->sock_fd, &msg, 0) < 0) {
|
||||
DEBUG_LOG(LOGF_NtpIO, "Could not send to %s:%d from %s fd %d : %s",
|
||||
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
|
||||
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd,
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOGF_NtpIO, "Sent to %s:%d from %s fd %d",
|
||||
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
|
||||
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Send an unauthenticated packet to a given address */
|
||||
|
||||
int
|
||||
NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
|
||||
{
|
||||
return send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE, remote_addr, local_addr);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Send an authenticated packet to a given address */
|
||||
|
||||
int
|
||||
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len)
|
||||
{
|
||||
return send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE + auth_len, remote_addr, local_addr);
|
||||
}
|
||||
|
||||
23
ntp_io.h
23
ntp_io.h
@@ -33,34 +33,27 @@
|
||||
#include "addressing.h"
|
||||
|
||||
/* Function to initialise the module. */
|
||||
extern void NIO_Initialise(void);
|
||||
extern void NIO_Initialise(int family);
|
||||
|
||||
/* Function to finalise the module */
|
||||
extern void NIO_Finalise(void);
|
||||
|
||||
/* Function to obtain a socket for sending client packets */
|
||||
extern int NIO_OpenClientSocket(NTP_Remote_Address *remote_addr);
|
||||
extern int NIO_GetClientSocket(NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* Function to obtain a socket for sending server/peer packets */
|
||||
extern int NIO_OpenServerSocket(NTP_Remote_Address *remote_addr);
|
||||
extern int NIO_GetServerSocket(NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* Function to close a socket returned by NIO_OpenClientSocket() */
|
||||
/* Function to close a socket returned by NIO_GetClientSocket() */
|
||||
extern void NIO_CloseClientSocket(int sock_fd);
|
||||
|
||||
/* Function to close a socket returned by NIO_OpenServerSocket() */
|
||||
extern void NIO_CloseServerSocket(int sock_fd);
|
||||
|
||||
/* Function to check if socket is a server socket */
|
||||
extern int NIO_IsServerSocket(int sock_fd);
|
||||
|
||||
/* Function to check if a server socket is currently open */
|
||||
extern int NIO_IsServerSocketOpen(void);
|
||||
|
||||
/* Function to check if client packets can be sent to a server */
|
||||
extern int NIO_IsServerConnectable(NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* Function to transmit a packet */
|
||||
extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
|
||||
NTP_Local_Address *local_addr, int length, int process_tx);
|
||||
extern int NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr);
|
||||
|
||||
/* Function to transmit an authenticated packet */
|
||||
extern int NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len);
|
||||
|
||||
#endif /* GOT_NTP_IO_H */
|
||||
|
||||
814
ntp_io_linux.c
814
ntp_io_linux.c
@@ -1,814 +0,0 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016-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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Functions for NTP I/O specific to Linux
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "array.h"
|
||||
#include "conf.h"
|
||||
#include "hwclock.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "ntp_core.h"
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_io_linux.h"
|
||||
#include "ntp_sources.h"
|
||||
#include "sched.h"
|
||||
#include "socket.h"
|
||||
#include "sys_linux.h"
|
||||
#include "util.h"
|
||||
|
||||
struct Interface {
|
||||
char name[IF_NAMESIZE];
|
||||
int if_index;
|
||||
int phc_fd;
|
||||
int phc_mode;
|
||||
int phc_nocrossts;
|
||||
/* Link speed in mbit/s */
|
||||
int link_speed;
|
||||
/* Start of UDP data at layer 2 for IPv4 and IPv6 */
|
||||
int l2_udp4_ntp_start;
|
||||
int l2_udp6_ntp_start;
|
||||
/* Precision of PHC readings */
|
||||
double precision;
|
||||
/* Compensation of errors in TX and RX timestamping */
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
HCL_Instance clock;
|
||||
};
|
||||
|
||||
/* Number of PHC readings per HW clock sample */
|
||||
#define PHC_READINGS 10
|
||||
|
||||
/* Minimum interval between PHC readings */
|
||||
#define MIN_PHC_POLL -6
|
||||
|
||||
/* Maximum acceptable offset between HW and daemon/kernel timestamp */
|
||||
#define MAX_TS_DELAY 1.0
|
||||
|
||||
/* Array of Interfaces */
|
||||
static ARR_Instance interfaces;
|
||||
|
||||
/* RX/TX and TX-specific timestamping socket options */
|
||||
static int ts_flags;
|
||||
static int ts_tx_flags;
|
||||
|
||||
/* Flag indicating the socket options can't be changed in control messages */
|
||||
static int permanent_ts_options;
|
||||
|
||||
/* When sending client requests to a close and fast server, it is possible that
|
||||
a response will be received before the HW transmit timestamp of the request
|
||||
itself. To avoid processing of the response without the HW timestamp, we
|
||||
monitor events returned by select() and suspend reading of packets from the
|
||||
receive queue for up to 200 microseconds. As the requests are normally
|
||||
separated by at least 200 milliseconds, it is sufficient to monitor and
|
||||
suspend one socket at a time. */
|
||||
static int monitored_socket;
|
||||
static int suspended_socket;
|
||||
static SCH_TimeoutID resume_timeout_id;
|
||||
|
||||
#define RESUME_TIMEOUT 200.0e-6
|
||||
|
||||
/* Unbound socket keeping the kernel RX timestamping permanently enabled
|
||||
in order to avoid a race condition between receiving a server response
|
||||
and the kernel actually starting to timestamp received packets after
|
||||
enabling the timestamping and sending a request */
|
||||
static int dummy_rxts_socket;
|
||||
|
||||
#define INVALID_SOCK_FD -3
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
add_interface(CNF_HwTsInterface *conf_iface)
|
||||
{
|
||||
struct ethtool_ts_info ts_info;
|
||||
struct hwtstamp_config ts_config;
|
||||
struct ifreq req;
|
||||
int sock_fd, if_index, phc_fd, req_hwts_flags, rx_filter;
|
||||
unsigned int i;
|
||||
struct Interface *iface;
|
||||
|
||||
/* Check if the interface was not already added */
|
||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||
if (!strcmp(conf_iface->name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
|
||||
return 1;
|
||||
}
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return 0;
|
||||
|
||||
memset(&req, 0, sizeof (req));
|
||||
memset(&ts_info, 0, sizeof (ts_info));
|
||||
|
||||
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", conf_iface->name) >=
|
||||
sizeof (req.ifr_name)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ioctl(sock_fd, SIOCGIFINDEX, &req)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCGIFINDEX", strerror(errno));
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if_index = req.ifr_ifindex;
|
||||
|
||||
ts_info.cmd = ETHTOOL_GET_TS_INFO;
|
||||
req.ifr_data = (char *)&ts_info;
|
||||
|
||||
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
req_hwts_flags = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_TX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||
if ((ts_info.so_timestamping & req_hwts_flags) != req_hwts_flags) {
|
||||
DEBUG_LOG("HW timestamping not supported on %s", req.ifr_name);
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ts_info.phc_index < 0) {
|
||||
DEBUG_LOG("PHC missing on %s", req.ifr_name);
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (conf_iface->rxfilter) {
|
||||
case CNF_HWTS_RXFILTER_ANY:
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL))
|
||||
rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||
else
|
||||
#endif
|
||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_ALL))
|
||||
rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
else
|
||||
rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
break;
|
||||
case CNF_HWTS_RXFILTER_NONE:
|
||||
rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
break;
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
||||
case CNF_HWTS_RXFILTER_NTP:
|
||||
rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
break;
|
||||
}
|
||||
|
||||
ts_config.flags = 0;
|
||||
ts_config.tx_type = HWTSTAMP_TX_ON;
|
||||
ts_config.rx_filter = rx_filter;
|
||||
req.ifr_data = (char *)&ts_config;
|
||||
|
||||
if (ioctl(sock_fd, SIOCSHWTSTAMP, &req)) {
|
||||
LOG(errno == EPERM ? LOGS_ERR : LOGS_DEBUG,
|
||||
"ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno));
|
||||
|
||||
/* Check the current timestamping configuration in case this interface
|
||||
allows only reading of the configuration and it was already configured
|
||||
as requested */
|
||||
req.ifr_data = (char *)&ts_config;
|
||||
#ifdef SIOCGHWTSTAMP
|
||||
if (ioctl(sock_fd, SIOCGHWTSTAMP, &req) ||
|
||||
ts_config.tx_type != HWTSTAMP_TX_ON || ts_config.rx_filter != rx_filter)
|
||||
#endif
|
||||
{
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SCK_CloseSocket(sock_fd);
|
||||
|
||||
phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
|
||||
if (phc_fd < 0)
|
||||
return 0;
|
||||
|
||||
iface = ARR_GetNewElement(interfaces);
|
||||
|
||||
snprintf(iface->name, sizeof (iface->name), "%s", conf_iface->name);
|
||||
iface->if_index = if_index;
|
||||
iface->phc_fd = phc_fd;
|
||||
iface->phc_mode = 0;
|
||||
iface->phc_nocrossts = conf_iface->nocrossts;
|
||||
|
||||
/* Start with 1 gbit and no VLANs or IPv4/IPv6 options */
|
||||
iface->link_speed = 1000;
|
||||
iface->l2_udp4_ntp_start = 42;
|
||||
iface->l2_udp6_ntp_start = 62;
|
||||
|
||||
iface->precision = conf_iface->precision;
|
||||
iface->tx_comp = conf_iface->tx_comp;
|
||||
iface->rx_comp = conf_iface->rx_comp;
|
||||
|
||||
iface->clock = HCL_CreateInstance(conf_iface->min_samples, conf_iface->max_samples,
|
||||
UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL)));
|
||||
|
||||
LOG(LOGS_INFO, "Enabled HW timestamping %son %s",
|
||||
ts_config.rx_filter == HWTSTAMP_FILTER_NONE ? "(TX only) " : "", iface->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
add_all_interfaces(CNF_HwTsInterface *conf_iface_all)
|
||||
{
|
||||
CNF_HwTsInterface conf_iface;
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
int r;
|
||||
|
||||
conf_iface = *conf_iface_all;
|
||||
|
||||
if (getifaddrs(&ifaddr)) {
|
||||
DEBUG_LOG("getifaddrs() failed : %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||
conf_iface.name = ifa->ifa_name;
|
||||
if (add_interface(&conf_iface))
|
||||
r = 1;
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
|
||||
/* Return success if at least one interface was added */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
update_interface_speed(struct Interface *iface)
|
||||
{
|
||||
struct ethtool_cmd cmd;
|
||||
struct ifreq req;
|
||||
int sock_fd, link_speed;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return;
|
||||
|
||||
memset(&req, 0, sizeof (req));
|
||||
memset(&cmd, 0, sizeof (cmd));
|
||||
|
||||
snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", iface->name);
|
||||
cmd.cmd = ETHTOOL_GSET;
|
||||
req.ifr_data = (char *)&cmd;
|
||||
|
||||
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
SCK_CloseSocket(sock_fd);
|
||||
|
||||
link_speed = ethtool_cmd_speed(&cmd);
|
||||
|
||||
if (iface->link_speed != link_speed) {
|
||||
iface->link_speed = link_speed;
|
||||
DEBUG_LOG("Updated speed of %s to %d Mb/s", iface->name, link_speed);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO) || defined(HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW)
|
||||
static int
|
||||
check_timestamping_option(int option)
|
||||
{
|
||||
int sock_fd;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return 0;
|
||||
|
||||
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, option)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_dummy_socket(void)
|
||||
{
|
||||
int sock_fd, events = 0;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return INVALID_SOCK_FD;
|
||||
|
||||
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, 1, &events)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Linux_Initialise(void)
|
||||
{
|
||||
CNF_HwTsInterface *conf_iface;
|
||||
unsigned int i;
|
||||
int hwts;
|
||||
|
||||
interfaces = ARR_CreateInstance(sizeof (struct Interface));
|
||||
|
||||
/* Enable HW timestamping on specified interfaces. If "*" was specified, try
|
||||
all interfaces. If no interface was specified, enable SW timestamping. */
|
||||
|
||||
for (i = hwts = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
|
||||
if (!strcmp("*", conf_iface->name))
|
||||
continue;
|
||||
if (!add_interface(conf_iface))
|
||||
LOG_FATAL("Could not enable HW timestamping on %s", conf_iface->name);
|
||||
hwts = 1;
|
||||
}
|
||||
|
||||
for (i = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
|
||||
if (strcmp("*", conf_iface->name))
|
||||
continue;
|
||||
if (add_all_interfaces(conf_iface))
|
||||
hwts = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
ts_flags = SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE;
|
||||
ts_tx_flags = SOF_TIMESTAMPING_TX_SOFTWARE;
|
||||
|
||||
if (hwts) {
|
||||
ts_flags |= SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
|
||||
ts_tx_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO
|
||||
if (check_timestamping_option(SOF_TIMESTAMPING_OPT_PKTINFO))
|
||||
ts_flags |= SOF_TIMESTAMPING_OPT_PKTINFO;
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW
|
||||
if (check_timestamping_option(SOF_TIMESTAMPING_OPT_TX_SWHW))
|
||||
ts_flags |= SOF_TIMESTAMPING_OPT_TX_SWHW;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Enable IP_PKTINFO in messages looped back to the error queue */
|
||||
ts_flags |= SOF_TIMESTAMPING_OPT_CMSG;
|
||||
|
||||
/* Kernels before 4.7 ignore timestamping flags set in control messages */
|
||||
permanent_ts_options = !SYS_Linux_CheckKernelVersion(4, 7);
|
||||
|
||||
monitored_socket = INVALID_SOCK_FD;
|
||||
suspended_socket = INVALID_SOCK_FD;
|
||||
dummy_rxts_socket = INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Linux_Finalise(void)
|
||||
{
|
||||
struct Interface *iface;
|
||||
unsigned int i;
|
||||
|
||||
if (dummy_rxts_socket != INVALID_SOCK_FD)
|
||||
SCK_CloseSocket(dummy_rxts_socket);
|
||||
|
||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||
iface = ARR_GetElement(interfaces, i);
|
||||
HCL_DestroyInstance(iface->clock);
|
||||
close(iface->phc_fd);
|
||||
}
|
||||
|
||||
ARR_DestroyInstance(interfaces);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
|
||||
{
|
||||
int val, flags;
|
||||
|
||||
if (!ts_flags)
|
||||
return 0;
|
||||
|
||||
/* Enable SCM_TIMESTAMPING control messages and the socket's error queue in
|
||||
order to receive our transmitted packets with more accurate timestamps */
|
||||
|
||||
val = 1;
|
||||
flags = ts_flags;
|
||||
|
||||
if (client_only || permanent_ts_options)
|
||||
flags |= ts_tx_flags;
|
||||
|
||||
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_SELECT_ERR_QUEUE, val)) {
|
||||
ts_flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, flags)) {
|
||||
ts_flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*events |= SCH_FILE_EXCEPTION;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
resume_socket(int sock_fd)
|
||||
{
|
||||
if (monitored_socket == sock_fd)
|
||||
monitored_socket = INVALID_SOCK_FD;
|
||||
|
||||
if (sock_fd == INVALID_SOCK_FD || sock_fd != suspended_socket)
|
||||
return;
|
||||
|
||||
suspended_socket = INVALID_SOCK_FD;
|
||||
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_INPUT, 1);
|
||||
|
||||
DEBUG_LOG("Resumed RX processing %s timeout fd=%d",
|
||||
resume_timeout_id ? "before" : "on", sock_fd);
|
||||
|
||||
if (resume_timeout_id) {
|
||||
SCH_RemoveTimeout(resume_timeout_id);
|
||||
resume_timeout_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
resume_timeout(void *arg)
|
||||
{
|
||||
resume_timeout_id = 0;
|
||||
resume_socket(suspended_socket);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
suspend_socket(int sock_fd)
|
||||
{
|
||||
resume_socket(suspended_socket);
|
||||
|
||||
suspended_socket = sock_fd;
|
||||
|
||||
SCH_SetFileHandlerEvent(suspended_socket, SCH_FILE_INPUT, 0);
|
||||
resume_timeout_id = SCH_AddTimeoutByDelay(RESUME_TIMEOUT, resume_timeout, NULL);
|
||||
|
||||
DEBUG_LOG("Suspended RX processing fd=%d", sock_fd);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_Linux_ProcessEvent(int sock_fd, int event)
|
||||
{
|
||||
if (sock_fd != monitored_socket)
|
||||
return 0;
|
||||
|
||||
if (event == SCH_FILE_INPUT) {
|
||||
suspend_socket(monitored_socket);
|
||||
monitored_socket = INVALID_SOCK_FD;
|
||||
|
||||
/* Don't process the message yet */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static struct Interface *
|
||||
get_interface(int if_index)
|
||||
{
|
||||
struct Interface *iface;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||
iface = ARR_GetElement(interfaces, i);
|
||||
if (iface->if_index != if_index)
|
||||
continue;
|
||||
|
||||
return iface;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
|
||||
NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family,
|
||||
int l2_length)
|
||||
{
|
||||
struct timespec sample_phc_ts, sample_sys_ts, sample_local_ts, ts;
|
||||
double rx_correction, ts_delay, phc_err, local_err;
|
||||
|
||||
if (HCL_NeedsNewSample(iface->clock, &local_ts->ts)) {
|
||||
if (!SYS_Linux_GetPHCSample(iface->phc_fd, iface->phc_nocrossts, iface->precision,
|
||||
&iface->phc_mode, &sample_phc_ts, &sample_sys_ts,
|
||||
&phc_err))
|
||||
return;
|
||||
|
||||
LCL_CookTime(&sample_sys_ts, &sample_local_ts, &local_err);
|
||||
HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts,
|
||||
phc_err + local_err);
|
||||
|
||||
update_interface_speed(iface);
|
||||
}
|
||||
|
||||
/* We need to transpose RX timestamps as hardware timestamps are normally
|
||||
preamble timestamps and RX timestamps in NTP are supposed to be trailer
|
||||
timestamps. If we don't know the length of the packet at layer 2, we
|
||||
make an assumption that UDP data start at the same position as in the
|
||||
last transmitted packet which had a HW TX timestamp. */
|
||||
if (rx_ntp_length && iface->link_speed) {
|
||||
if (!l2_length)
|
||||
l2_length = (family == IPADDR_INET4 ? iface->l2_udp4_ntp_start :
|
||||
iface->l2_udp6_ntp_start) + rx_ntp_length;
|
||||
|
||||
/* Include the frame check sequence (FCS) */
|
||||
l2_length += 4;
|
||||
|
||||
rx_correction = l2_length / (1.0e6 / 8 * iface->link_speed);
|
||||
|
||||
UTI_AddDoubleToTimespec(hw_ts, rx_correction, hw_ts);
|
||||
}
|
||||
|
||||
if (!HCL_CookTime(iface->clock, hw_ts, &ts, &local_err))
|
||||
return;
|
||||
|
||||
if (!rx_ntp_length && iface->tx_comp)
|
||||
UTI_AddDoubleToTimespec(&ts, iface->tx_comp, &ts);
|
||||
else if (rx_ntp_length && iface->rx_comp)
|
||||
UTI_AddDoubleToTimespec(&ts, -iface->rx_comp, &ts);
|
||||
|
||||
ts_delay = UTI_DiffTimespecsToDouble(&local_ts->ts, &ts);
|
||||
|
||||
if (fabs(ts_delay) > MAX_TS_DELAY) {
|
||||
DEBUG_LOG("Unacceptable timestamp delay %.9f", ts_delay);
|
||||
return;
|
||||
}
|
||||
|
||||
local_ts->ts = ts;
|
||||
local_ts->err = local_err;
|
||||
local_ts->source = NTP_TS_HARDWARE;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Extract UDP data from a layer 2 message. Supported is Ethernet
|
||||
with optional VLAN tags. */
|
||||
|
||||
static int
|
||||
extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
||||
{
|
||||
unsigned char *msg_start = msg;
|
||||
|
||||
remote_addr->ip_addr.family = IPADDR_UNSPEC;
|
||||
remote_addr->port = 0;
|
||||
|
||||
/* Skip MACs */
|
||||
if (len < 12)
|
||||
return 0;
|
||||
len -= 12, msg += 12;
|
||||
|
||||
/* Skip VLAN tag(s) if present */
|
||||
while (len >= 4 && msg[0] == 0x81 && msg[1] == 0x00)
|
||||
len -= 4, msg += 4;
|
||||
|
||||
/* Skip IPv4 or IPv6 ethertype */
|
||||
if (len < 2 || !((msg[0] == 0x08 && msg[1] == 0x00) ||
|
||||
(msg[0] == 0x86 && msg[1] == 0xdd)))
|
||||
return 0;
|
||||
len -= 2, msg += 2;
|
||||
|
||||
/* Parse destination address and port from IPv4/IPv6 and UDP headers */
|
||||
if (len >= 20 && msg[0] >> 4 == 4) {
|
||||
int ihl = (msg[0] & 0xf) * 4;
|
||||
uint32_t addr;
|
||||
|
||||
if (len < ihl + 8 || msg[9] != 17)
|
||||
return 0;
|
||||
|
||||
memcpy(&addr, msg + 16, sizeof (addr));
|
||||
remote_addr->ip_addr.addr.in4 = ntohl(addr);
|
||||
remote_addr->port = ntohs(*(uint16_t *)(msg + ihl + 2));
|
||||
remote_addr->ip_addr.family = IPADDR_INET4;
|
||||
len -= ihl + 8, msg += ihl + 8;
|
||||
#ifdef FEAT_IPV6
|
||||
} else if (len >= 48 && msg[0] >> 4 == 6) {
|
||||
int eh_len, next_header = msg[6];
|
||||
|
||||
memcpy(&remote_addr->ip_addr.addr.in6, msg + 24, sizeof (remote_addr->ip_addr.addr.in6));
|
||||
len -= 40, msg += 40;
|
||||
|
||||
/* Skip IPv6 extension headers if present */
|
||||
while (next_header != 17) {
|
||||
switch (next_header) {
|
||||
case 44: /* Fragment Header */
|
||||
/* Process only the first fragment */
|
||||
if (ntohs(*(uint16_t *)(msg + 2)) >> 3 != 0)
|
||||
return 0;
|
||||
eh_len = 8;
|
||||
break;
|
||||
case 0: /* Hop-by-Hop Options */
|
||||
case 43: /* Routing Header */
|
||||
case 60: /* Destination Options */
|
||||
case 135: /* Mobility Header */
|
||||
eh_len = 8 * (msg[1] + 1);
|
||||
break;
|
||||
case 51: /* Authentication Header */
|
||||
eh_len = 4 * (msg[1] + 2);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (eh_len < 8 || len < eh_len + 8)
|
||||
return 0;
|
||||
|
||||
next_header = msg[0];
|
||||
len -= eh_len, msg += eh_len;
|
||||
}
|
||||
|
||||
remote_addr->port = ntohs(*(uint16_t *)(msg + 2));
|
||||
remote_addr->ip_addr.family = IPADDR_INET6;
|
||||
len -= 8, msg += 8;
|
||||
#endif
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move the message to fix alignment of its fields */
|
||||
if (len > 0)
|
||||
memmove(msg_start, msg, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *local_ts, int event)
|
||||
{
|
||||
struct Interface *iface;
|
||||
int is_tx, ts_if_index, l2_length;
|
||||
|
||||
is_tx = event == SCH_FILE_EXCEPTION;
|
||||
iface = NULL;
|
||||
|
||||
ts_if_index = message->timestamp.if_index;
|
||||
if (ts_if_index == INVALID_IF_INDEX)
|
||||
ts_if_index = message->if_index;
|
||||
l2_length = message->timestamp.l2_length;
|
||||
|
||||
if (!UTI_IsZeroTimespec(&message->timestamp.hw)) {
|
||||
iface = get_interface(ts_if_index);
|
||||
if (iface) {
|
||||
process_hw_timestamp(iface, &message->timestamp.hw, local_ts, !is_tx ? message->length : 0,
|
||||
message->remote_addr.ip.ip_addr.family, l2_length);
|
||||
} else {
|
||||
DEBUG_LOG("HW clock not found for interface %d", ts_if_index);
|
||||
}
|
||||
|
||||
/* If a HW transmit timestamp was received, resume processing
|
||||
of non-error messages on this socket */
|
||||
if (is_tx)
|
||||
resume_socket(local_addr->sock_fd);
|
||||
}
|
||||
|
||||
if (local_ts->source == NTP_TS_DAEMON && !UTI_IsZeroTimespec(&message->timestamp.kernel) &&
|
||||
(!is_tx || UTI_IsZeroTimespec(&message->timestamp.hw))) {
|
||||
LCL_CookTime(&message->timestamp.kernel, &local_ts->ts, &local_ts->err);
|
||||
local_ts->source = NTP_TS_KERNEL;
|
||||
}
|
||||
|
||||
/* If the kernel is slow with enabling RX timestamping, open a dummy
|
||||
socket to keep the kernel RX timestamping permanently enabled */
|
||||
if (!is_tx && local_ts->source == NTP_TS_DAEMON && ts_flags) {
|
||||
DEBUG_LOG("Missing kernel RX timestamp");
|
||||
if (dummy_rxts_socket == INVALID_SOCK_FD)
|
||||
dummy_rxts_socket = open_dummy_socket();
|
||||
}
|
||||
|
||||
/* Return the message if it's not received from the error queue */
|
||||
if (!is_tx)
|
||||
return 0;
|
||||
|
||||
/* The data from the error queue includes all layers up to UDP. We have to
|
||||
extract the UDP data and also the destination address with port as there
|
||||
currently doesn't seem to be a better way to get them both. */
|
||||
l2_length = message->length;
|
||||
message->length = extract_udp_data(message->data, &message->remote_addr.ip, message->length);
|
||||
|
||||
DEBUG_LOG("Extracted message for %s fd=%d len=%d",
|
||||
UTI_IPSockAddrToString(&message->remote_addr.ip),
|
||||
local_addr->sock_fd, message->length);
|
||||
|
||||
/* Update assumed position of UDP data at layer 2 for next received packet */
|
||||
if (iface && message->length) {
|
||||
if (message->remote_addr.ip.ip_addr.family == IPADDR_INET4)
|
||||
iface->l2_udp4_ntp_start = l2_length - message->length;
|
||||
else if (message->remote_addr.ip.ip_addr.family == IPADDR_INET6)
|
||||
iface->l2_udp6_ntp_start = l2_length - message->length;
|
||||
}
|
||||
|
||||
/* Drop the message if it has no timestamp or its processing failed */
|
||||
if (local_ts->source == NTP_TS_DAEMON) {
|
||||
DEBUG_LOG("Missing TX timestamp");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (message->length < NTP_HEADER_LENGTH)
|
||||
return 1;
|
||||
|
||||
NSR_ProcessTx(&message->remote_addr.ip, local_addr, local_ts, message->data, message->length);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Linux_RequestTxTimestamp(SCK_Message *message, int sock_fd)
|
||||
{
|
||||
if (!ts_flags)
|
||||
return;
|
||||
|
||||
/* If a HW transmit timestamp is requested on a client socket, monitor
|
||||
events on the socket in order to avoid processing of a fast response
|
||||
without the HW timestamp of the request */
|
||||
if (ts_tx_flags & SOF_TIMESTAMPING_TX_HARDWARE && !NIO_IsServerSocket(sock_fd))
|
||||
monitored_socket = sock_fd;
|
||||
|
||||
/* Check if TX timestamping is disabled on this socket */
|
||||
if (permanent_ts_options || !NIO_IsServerSocket(sock_fd))
|
||||
return;
|
||||
|
||||
message->timestamp.tx_flags = ts_tx_flags;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Linux_NotifySocketClosing(int sock_fd)
|
||||
{
|
||||
resume_socket(sock_fd);
|
||||
}
|
||||
@@ -1,47 +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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This is the header file for the Linux-specific NTP socket I/O bits.
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTP_IO_LINUX_H
|
||||
#define GOT_NTP_IO_LINUX_H
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
extern void NIO_Linux_Initialise(void);
|
||||
|
||||
extern void NIO_Linux_Finalise(void);
|
||||
|
||||
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
|
||||
|
||||
extern int NIO_Linux_ProcessEvent(int sock_fd, int event);
|
||||
|
||||
extern int NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *local_ts, int event);
|
||||
|
||||
extern void NIO_Linux_RequestTxTimestamp(SCK_Message *message, int sock_fd);
|
||||
|
||||
extern void NIO_Linux_NotifySocketClosing(int sock_fd);
|
||||
|
||||
#endif
|
||||
341
ntp_signd.c
341
ntp_signd.c
@@ -1,341 +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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Support for MS-SNTP authentication in Samba (ntp_signd)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "array.h"
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_signd.h"
|
||||
#include "sched.h"
|
||||
#include "socket.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Declarations per samba/source4/librpc/idl/ntp_signd.idl */
|
||||
|
||||
#define SIGND_VERSION 0
|
||||
|
||||
typedef enum {
|
||||
SIGN_TO_CLIENT = 0,
|
||||
ASK_SERVER_TO_SIGN = 1,
|
||||
CHECK_SERVER_SIGNATURE = 2,
|
||||
SIGNING_SUCCESS = 3,
|
||||
SIGNING_FAILURE = 4,
|
||||
} SigndOp;
|
||||
|
||||
typedef struct {
|
||||
uint32_t length;
|
||||
uint32_t version;
|
||||
uint32_t op;
|
||||
uint16_t packet_id;
|
||||
uint16_t _pad;
|
||||
uint32_t key_id;
|
||||
NTP_Packet packet_to_sign;
|
||||
} SigndRequest;
|
||||
|
||||
typedef struct {
|
||||
uint32_t length;
|
||||
uint32_t version;
|
||||
uint32_t op;
|
||||
uint32_t packet_id;
|
||||
NTP_Packet signed_packet;
|
||||
} SigndResponse;
|
||||
|
||||
typedef struct {
|
||||
NTP_Remote_Address remote_addr;
|
||||
NTP_Local_Address local_addr;
|
||||
|
||||
int sent;
|
||||
int received;
|
||||
int request_length;
|
||||
struct timespec request_ts;
|
||||
SigndRequest request;
|
||||
SigndResponse response;
|
||||
} SignInstance;
|
||||
|
||||
/* As the communication with ntp_signd is asynchronous, incoming packets are
|
||||
saved in a queue in order to avoid loss when they come in bursts */
|
||||
|
||||
#define MAX_QUEUE_LENGTH 16U
|
||||
#define NEXT_QUEUE_INDEX(index) (((index) + 1) % MAX_QUEUE_LENGTH)
|
||||
#define IS_QUEUE_EMPTY() (queue_head == queue_tail)
|
||||
|
||||
/* Fixed-size array of SignInstance */
|
||||
static ARR_Instance queue;
|
||||
static unsigned int queue_head;
|
||||
static unsigned int queue_tail;
|
||||
|
||||
#define INVALID_SOCK_FD (-6)
|
||||
|
||||
/* Unix domain socket connected to ntp_signd */
|
||||
static int sock_fd;
|
||||
|
||||
/* Flag indicating if the MS-SNTP authentication is enabled */
|
||||
static int enabled;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void read_write_socket(int sock_fd, int event, void *anything);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
close_socket(void)
|
||||
{
|
||||
SCH_RemoveFileHandler(sock_fd);
|
||||
SCK_CloseSocket(sock_fd);
|
||||
sock_fd = INVALID_SOCK_FD;
|
||||
|
||||
/* Empty the queue */
|
||||
queue_head = queue_tail = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_socket(void)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (sock_fd != INVALID_SOCK_FD)
|
||||
return 1;
|
||||
|
||||
if (snprintf(path, sizeof (path), "%s/socket", CNF_GetNtpSigndSocket()) >= sizeof (path)) {
|
||||
DEBUG_LOG("signd socket path too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sock_fd = SCK_OpenUnixStreamSocket(path, NULL, 0);
|
||||
if (sock_fd < 0) {
|
||||
sock_fd = INVALID_SOCK_FD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SCH_AddFileHandler(sock_fd, SCH_FILE_INPUT, read_write_socket, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
process_response(SignInstance *inst)
|
||||
{
|
||||
struct timespec ts;
|
||||
double delay;
|
||||
|
||||
if (ntohs(inst->request.packet_id) != ntohl(inst->response.packet_id)) {
|
||||
DEBUG_LOG("Invalid response ID");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ntohl(inst->response.op) != SIGNING_SUCCESS) {
|
||||
DEBUG_LOG("Signing failed");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the file descriptor is still valid */
|
||||
if (!NIO_IsServerSocket(inst->local_addr.sock_fd)) {
|
||||
DEBUG_LOG("Invalid NTP socket");
|
||||
return;
|
||||
}
|
||||
|
||||
SCH_GetLastEventTime(NULL, NULL, &ts);
|
||||
delay = UTI_DiffTimespecsToDouble(&ts, &inst->request_ts);
|
||||
|
||||
DEBUG_LOG("Signing succeeded (delay %f)", delay);
|
||||
|
||||
/* Send the signed NTP packet */
|
||||
NIO_SendPacket(&inst->response.signed_packet, &inst->remote_addr, &inst->local_addr,
|
||||
ntohl(inst->response.length) + sizeof (inst->response.length) -
|
||||
offsetof(SigndResponse, signed_packet), 0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
read_write_socket(int sock_fd, int event, void *anything)
|
||||
{
|
||||
SignInstance *inst;
|
||||
uint32_t response_length;
|
||||
int s;
|
||||
|
||||
inst = ARR_GetElement(queue, queue_head);
|
||||
|
||||
if (event == SCH_FILE_OUTPUT) {
|
||||
assert(!IS_QUEUE_EMPTY());
|
||||
assert(inst->sent < inst->request_length);
|
||||
|
||||
if (!inst->sent)
|
||||
SCH_GetLastEventTime(NULL, NULL, &inst->request_ts);
|
||||
|
||||
s = SCK_Send(sock_fd, (char *)&inst->request + inst->sent,
|
||||
inst->request_length - inst->sent, 0);
|
||||
|
||||
if (s < 0) {
|
||||
close_socket();
|
||||
return;
|
||||
}
|
||||
|
||||
inst->sent += s;
|
||||
|
||||
/* Try again later if the request is not complete yet */
|
||||
if (inst->sent < inst->request_length)
|
||||
return;
|
||||
|
||||
/* Disable output and wait for a response */
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 0);
|
||||
}
|
||||
|
||||
if (event == SCH_FILE_INPUT) {
|
||||
if (IS_QUEUE_EMPTY()) {
|
||||
DEBUG_LOG("Unexpected signd response");
|
||||
close_socket();
|
||||
return;
|
||||
}
|
||||
|
||||
assert(inst->received < sizeof (inst->response));
|
||||
s = SCK_Receive(sock_fd, (char *)&inst->response + inst->received,
|
||||
sizeof (inst->response) - inst->received, 0);
|
||||
|
||||
if (s <= 0) {
|
||||
close_socket();
|
||||
return;
|
||||
}
|
||||
|
||||
inst->received += s;
|
||||
|
||||
if (inst->received < sizeof (inst->response.length))
|
||||
return;
|
||||
|
||||
response_length = ntohl(inst->response.length) + sizeof (inst->response.length);
|
||||
|
||||
if (response_length < offsetof(SigndResponse, signed_packet) ||
|
||||
response_length > sizeof (SigndResponse)) {
|
||||
DEBUG_LOG("Invalid response length");
|
||||
close_socket();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for more data if not complete yet */
|
||||
if (inst->received < response_length)
|
||||
return;
|
||||
|
||||
process_response(inst);
|
||||
|
||||
/* Move the head and enable output for the next packet */
|
||||
queue_head = NEXT_QUEUE_INDEX(queue_head);
|
||||
if (!IS_QUEUE_EMPTY())
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NSD_Initialise()
|
||||
{
|
||||
sock_fd = INVALID_SOCK_FD;
|
||||
enabled = CNF_GetNtpSigndSocket() && CNF_GetNtpSigndSocket()[0];
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
queue = ARR_CreateInstance(sizeof (SignInstance));
|
||||
ARR_SetSize(queue, MAX_QUEUE_LENGTH);
|
||||
queue_head = queue_tail = 0;
|
||||
|
||||
LOG(LOGS_INFO, "MS-SNTP authentication enabled");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NSD_Finalise()
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
if (sock_fd != INVALID_SOCK_FD)
|
||||
close_socket();
|
||||
ARR_DestroyInstance(queue);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info,
|
||||
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
|
||||
{
|
||||
SignInstance *inst;
|
||||
|
||||
if (!enabled) {
|
||||
DEBUG_LOG("signd disabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (queue_head == NEXT_QUEUE_INDEX(queue_tail)) {
|
||||
DEBUG_LOG("signd queue full");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info->length != NTP_HEADER_LENGTH) {
|
||||
DEBUG_LOG("Invalid packet length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!open_socket())
|
||||
return 0;
|
||||
|
||||
inst = ARR_GetElement(queue, queue_tail);
|
||||
inst->remote_addr = *remote_addr;
|
||||
inst->local_addr = *local_addr;
|
||||
inst->sent = 0;
|
||||
inst->received = 0;
|
||||
inst->request_length = offsetof(SigndRequest, packet_to_sign) + info->length;
|
||||
|
||||
/* The length field doesn't include itself */
|
||||
inst->request.length = htonl(inst->request_length - sizeof (inst->request.length));
|
||||
inst->request.version = htonl(SIGND_VERSION);
|
||||
inst->request.op = htonl(SIGN_TO_CLIENT);
|
||||
inst->request.packet_id = htons(queue_tail);
|
||||
inst->request._pad = 0;
|
||||
inst->request.key_id = htonl(key_id);
|
||||
|
||||
memcpy(&inst->request.packet_to_sign, packet, info->length);
|
||||
|
||||
/* Enable output if there was no pending request */
|
||||
if (IS_QUEUE_EMPTY())
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
|
||||
|
||||
queue_tail = NEXT_QUEUE_INDEX(queue_tail);
|
||||
|
||||
DEBUG_LOG("Packet added to signd queue (%u:%u)", queue_head, queue_tail);
|
||||
|
||||
return 1;
|
||||
}
|
||||
42
ntp_signd.h
42
ntp_signd.h
@@ -1,42 +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 MS-SNTP authentication via Samba (ntp_signd) */
|
||||
|
||||
#ifndef GOT_NTP_SIGND_H
|
||||
#define GOT_NTP_SIGND_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "ntp.h"
|
||||
|
||||
/* Initialisation function */
|
||||
extern void NSD_Initialise(void);
|
||||
|
||||
/* Finalisation function */
|
||||
extern void NSD_Finalise(void);
|
||||
|
||||
/* Function to sign an NTP packet and send it */
|
||||
extern int NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info,
|
||||
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr);
|
||||
|
||||
#endif
|
||||
1249
ntp_sources.c
1249
ntp_sources.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
Reference in New Issue
Block a user