network time: introduce a client mode; closes #2012

This commit is contained in:
Franco Fichtner 2021-06-22 14:39:20 +02:00
parent 37cd6feca9
commit 2fa32cb3b4
6 changed files with 100 additions and 119 deletions

1
plist
View File

@ -31,7 +31,6 @@
/usr/local/etc/inc/plugins.inc.d/monit.inc
/usr/local/etc/inc/plugins.inc.d/netflow.inc
/usr/local/etc/inc/plugins.inc.d/ntpd.inc
/usr/local/etc/inc/plugins.inc.d/ntpd/ntpdate_sync_once.sh
/usr/local/etc/inc/plugins.inc.d/opendns.inc
/usr/local/etc/inc/plugins.inc.d/openssh.inc
/usr/local/etc/inc/plugins.inc.d/openvpn.inc

View File

@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2016 Franco Fichtner <franco@opnsense.org>
* Copyright (C) 2016-2021 Franco Fichtner <franco@opnsense.org>
* Copyright (C) 2004-2007 Scott Ullrich <sullrich@gmail.com>
* Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>
* All rights reserved.
@ -37,6 +37,8 @@ function ntpd_enabled()
function ntpd_services()
{
global $config;
$services = array();
if (!ntpd_enabled()) {
@ -46,9 +48,14 @@ function ntpd_services()
$pconfig = array();
$pconfig['name'] = 'ntpd';
$pconfig['description'] = gettext('Network Time Daemon');
$pconfig['php']['restart'] = array('ntpd_configure_start');
$pconfig['php']['start'] = array('ntpd_configure_start');
$pconfig['php']['restart'] = array('ntpd_configure_do');
$pconfig['php']['start'] = array('ntpd_configure_do');
$pconfig['pidfile'] = '/var/run/ntpd.pid';
if (!empty($config['ntpd']['clientmode'])) {
$pconfig['nocheck'] = true;
}
$services[] = $pconfig;
return $services;
@ -63,12 +70,24 @@ function ntpd_syslog()
return $logfacilities;
}
function ntpd_cron()
{
global $config;
$jobs = array();
if (ntpd_enabled() && !empty($config['ntpd']['clientmode'])) {
$jobs[]['autocron'] = array('pluginctl -s ntpd restart', '0', '2');
}
return $jobs;
}
function ntpd_configure()
{
return array(
'bootup' => array('ntpd_configure_defer'),
'local' => array('ntpd_configure_start'),
'newwanip' => array('ntpd_configure_defer'),
'bootup' => array('ntpd_configure_do'),
'local' => array('ntpd_configure_do'),
'newwanip' => array('ntpd_configure_do'),
);
}
@ -149,23 +168,11 @@ function ntpd_configure_pps($serialport)
return true;
}
function ntpd_configure_start($verbose = false)
{
ntpd_configure_do($verbose, true);
}
function ntpd_configure_defer($verbose = false)
{
ntpd_configure_do($verbose, false);
}
function ntpd_configure_do($verbose = false, $start_ntpd = true)
function ntpd_configure_do($verbose = false)
{
global $config;
if ($start_ntpd) {
killbypid('/var/run/ntpd.pid', 'TERM', true);
}
killbypid('/var/run/ntpd.pid', 'TERM', true);
if (!ntpd_enabled()) {
return;
@ -436,23 +443,20 @@ function ntpd_configure_do($verbose = false, $start_ntpd = true)
file_put_contents('/var/etc/ntpd.conf', $ntpcfg);
if (!$start_ntpd) {
/* write out the config and delay startup */
mwexec_bg('/usr/local/etc/inc/plugins.inc.d/ntpd/ntpdate_sync_once.sh');
if ($verbose) {
echo "deferred.\n";
}
return;
}
/* if /var/empty does not exist, create it */
@mkdir('/var/empty', 0775, true);
/* start opentpd, set time now and use new config */
mwexecf(
'/usr/local/sbin/ntpd -g -c %s -p %s',
array('/var/etc/ntpd.conf', '/var/run/ntpd.pid')
);
if (empty($config['ntpd']['clientmode'])) {
mwexecf(
'/usr/local/sbin/ntpd -g -c %s -p %s',
array('/var/etc/ntpd.conf', '/var/run/ntpd.pid')
);
} else {
mwexecf_bg(
'/usr/local/sbin/ntpd -q -g -c %s -p %s',
array('/var/etc/ntpd.conf', '/var/run/ntpd.pid')
);
}
if ($verbose) {
echo "done.\n";

View File

@ -1,46 +0,0 @@
#!/bin/sh
NOTSYNCED="true"
MAX_ATTEMPTS=3
SERVER=`/bin/cat /conf/config.xml | /usr/bin/grep timeservers | /usr/bin/cut -d">" -f2 | /usr/bin/cut -d"<" -f1`
if [ "${SERVER}" = "" ]; then
exit
fi
/bin/pkill -f ntpdate_sync_once.sh
ATTEMPT=1
# Loop until we're synchronized, but for a set number of attempts so we don't get stuck here forever.
while [ "$NOTSYNCED" = "true" ] && [ ${ATTEMPT} -le ${MAX_ATTEMPTS} ]; do
# Ensure that ntpd and ntpdate are not running so that the socket we want will be free.
while [ true ]; do
/usr/bin/killall ntpdate 2>/dev/null
/bin/pgrep ntpd
if [ $? -eq 0 ]; then
/usr/bin/killall ntpd 2>/dev/null
else
break
fi
done
sleep 1
/usr/local/sbin/ntpdate -s -t 5 ${SERVER}
if [ "$?" = "0" ]; then
NOTSYNCED="false"
else
sleep 5
ATTEMPT=`expr ${ATTEMPT} + 1`
fi
done
if [ "$NOTSYNCED" = "true" ]; then
echo "Giving up on time sync after ${MAX_ATTEMPTS} attempts." | /usr/bin/logger -t ntp;
else
echo "Successfully synced time after ${ATTEMPT} attempts." | /usr/bin/logger -t ntp;
fi
if [ -f /var/etc/ntpd.conf ]; then
echo "Starting NTP Daemon." | /usr/bin/logger -t ntp;
/usr/local/sbin/ntpd -g -c /var/etc/ntpd.conf -p /var/run/ntpd.pid
else
echo "NTP configuration file missing, not starting daemon." | /usr/bin/logger -t ntp;
fi

View File

@ -36,8 +36,25 @@ require_once("plugins.inc.d/ntpd.inc");
$a_ntpd = &config_read_array('ntpd');
$copy_fields = array('orphan', 'statsgraph', 'logpeer', 'logsys', 'clockstats', 'loopstats', 'interface',
'peerstats', 'noquery', 'noserve', 'kod', 'nomodify', 'nopeer', 'notrap', 'leapsec');
$copy_fields = [
'clientmode',
'clockstats',
'interface',
'kod',
'leapsec',
'logpeer',
'logsys',
'loopstats',
'nomodify',
'nopeer',
'noquery',
'noserve',
'notrap',
'orphan',
'peerstats',
'statsgraph',
];
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$pconfig = array();
@ -127,7 +144,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
write_config("Updated NTP Server Settings");
rrd_configure();
ntpd_configure_start();
ntpd_configure_do();
system_cron_configure();
header(url_safe('Location: /services_ntpd.php'));
exit;
@ -224,39 +242,6 @@ include("head.inc");
</tr>
</thead>
<tbody>
<tr>
<td><a id="help_for_interfaces" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext('Interface(s)') ?></td>
<td>
<?php
$interfaces = get_configured_interface_with_descr();
$carplist = get_configured_carp_interface_list();
foreach ($carplist as $cif => $carpip) {
$interfaces[$cif] = $carpip." (".get_vip_descr($carpip).")";
}
$aliaslist = get_configured_ip_aliases_list();
foreach ($aliaslist as $aliasip => $aliasif) {
$interfaces[$aliasip] = $aliasip." (".get_vip_descr($aliasip).")";
}?>
<select id="interface" name="interface[]" multiple="multiple" class="selectpicker">
<?php
foreach ($interfaces as $iface => $ifacename):
if (!is_ipaddr(get_interface_ip($iface)) && !is_ipaddr($iface)) {
continue;
}?>
<option value="<?=$iface;?>" <?= !empty($pconfig['interface']) && in_array($iface, $pconfig['interface']) ? 'selected="selected"' : '' ?>>
<?=htmlspecialchars($ifacename);?>
</option>
<?php
endforeach;?>
</select>
<div class="hidden" data-for="help_for_interfaces">
<?=gettext("Interfaces without an IP address will not be shown."); ?>
<br />
<br /><?=gettext("Selecting no interfaces will listen on all interfaces with a wildcard."); ?>
<br /><?=gettext("Selecting all interfaces will explicitly listen on only the interfaces/IPs specified."); ?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_timeservers" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext('Time servers') ?></td>
<td>
@ -309,6 +294,45 @@ include("head.inc");
</div>
</td>
</tr>
<tr>
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext('Client mode') ?></td>
<td>
<input name="clientmode" type="checkbox" id="clientmode" <?=!empty($pconfig['clientmode']) ? ' checked="checked"' : '' ?> />
<?= gettext('Do not persist the NTP server to synchronize time') ?>
</td>
</tr>
<tr>
<td><a id="help_for_interfaces" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext('Interfaces') ?></td>
<td>
<?php
$interfaces = get_configured_interface_with_descr();
$carplist = get_configured_carp_interface_list();
foreach ($carplist as $cif => $carpip) {
$interfaces[$cif] = $carpip." (".get_vip_descr($carpip).")";
}
$aliaslist = get_configured_ip_aliases_list();
foreach ($aliaslist as $aliasip => $aliasif) {
$interfaces[$aliasip] = $aliasip." (".get_vip_descr($aliasip).")";
}?>
<select id="interface" name="interface[]" multiple="multiple" class="selectpicker" title="<?= html_safe(gettext('All (recommended)')) ?>">
<?php
foreach ($interfaces as $iface => $ifacename):
if (!is_ipaddr(get_interface_ip($iface)) && !is_ipaddr($iface)) {
continue;
}?>
<option value="<?=$iface;?>" <?= !empty($pconfig['interface']) && in_array($iface, $pconfig['interface']) ? 'selected="selected"' : '' ?>>
<?=htmlspecialchars($ifacename);?>
</option>
<?php
endforeach;?>
</select>
<div class="hidden" data-for="help_for_interfaces">
<?=gettext("Interfaces without an IP address will not be shown."); ?>
<br /><?=gettext("Selecting no interfaces will listen on all interfaces with a wildcard."); ?>
<br /><?=gettext("Selecting all interfaces will explicitly listen on only the interfaces/IPs specified."); ?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_orphan" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext('Orphan mode') ?></td>
<td>

View File

@ -65,7 +65,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$gps['initcmd']= base64_encode($gps['initcmd']);
$config['ntpd']['gps'] = $gps;
write_config("Updated NTP GPS Settings");
ntpd_configure_start();
ntpd_configure_do();
header(url_safe('Location: /services_ntpd_gps.php'));
exit;
}

View File

@ -60,7 +60,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
}
$config['ntpd']['pps'] = $pps;
write_config("Updated NTP PPS Settings");
ntpd_configure_start();
ntpd_configure_do();
header(url_safe('Location: /services_ntpd_pps.php'));
exit;
}