From dddb4dd85a1f27fb23625233671b0d7dcae3697b Mon Sep 17 00:00:00 2001 From: Matthew Otto Date: Sun, 4 Jan 2026 18:40:26 -0600 Subject: [PATCH 01/12] add NTP data view --- net/chrony/Makefile | 2 +- net/chrony/pkg-descr | 4 ++++ .../OPNsense/Chrony/Api/ServiceController.php | 11 +++++++++++ .../mvc/app/views/OPNsense/Chrony/general.volt | 11 +++++++++++ .../service/conf/actions.d/actions_chrony.conf | 6 ++++++ 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/net/chrony/Makefile b/net/chrony/Makefile index d4d807ea8..00a06140d 100644 --- a/net/chrony/Makefile +++ b/net/chrony/Makefile @@ -1,5 +1,5 @@ PLUGIN_NAME= chrony -PLUGIN_VERSION= 1.5 +PLUGIN_VERSION= 1.6 PLUGIN_REVISION= 3 PLUGIN_COMMENT= Chrony time synchronisation PLUGIN_DEPENDS= chrony diff --git a/net/chrony/pkg-descr b/net/chrony/pkg-descr index f38222784..fae71365b 100644 --- a/net/chrony/pkg-descr +++ b/net/chrony/pkg-descr @@ -4,6 +4,10 @@ better in virtual environments. Plugin Changelog ---------------- +1.6 + +* Add NTP data tab + 1.5 * Allow adding a fallback NTP when using NTS diff --git a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/Api/ServiceController.php b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/Api/ServiceController.php index e3a681390..2c88330d0 100644 --- a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/Api/ServiceController.php +++ b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/Api/ServiceController.php @@ -82,4 +82,15 @@ class ServiceController extends ApiMutableServiceControllerBase $response = $backend->configdRun("chrony chronyauthdata"); return array("response" => $response); } + + /** + * show chrony ntpdata + * @return array + */ + public function chronyntpdataAction() + { + $backend = new Backend(); + $response = $backend->configdRun("chrony chronyntpdata"); + return array("response" => $response); + } } diff --git a/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/general.volt b/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/general.volt index 40d7552e9..0cf9be238 100644 --- a/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/general.volt +++ b/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/general.volt @@ -31,6 +31,7 @@
  • {{ lang._('Source Stats') }}
  • {{ lang._('Tracking') }}
  • {{ lang._('Auth Data') }}
  • +
  • {{ lang._('NTP Data') }}
  • @@ -55,6 +56,9 @@
    
         
    +
    +
    
    +    
    From 198400ec57b8b59359cbd443cade17d06ae1c64c Mon Sep 17 00:00:00 2001 From: Matthew Otto Date: Mon, 5 Jan 2026 11:00:11 -0600 Subject: [PATCH 04/12] add local / orphan mode support (#5115) --- .../OPNsense/Chrony/forms/general.xml | 44 ++++++++++------- .../app/models/OPNsense/Chrony/General.xml | 32 ++++++++----- .../templates/OPNsense/Chrony/chrony.conf | 47 ++++++++++--------- 3 files changed, 74 insertions(+), 49 deletions(-) diff --git a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml index 3b6b358ff..be7d29794 100644 --- a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml +++ b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml @@ -5,12 +5,40 @@ checkbox Enable Chrony time daemon. + + general.peers + + + select_multiple + true + Set as many NTP peers you need. + + + general.localstratum + + text + (1-15) Local mode allows the system clock to be used when no other clocks are available. The number here specifies the stratum reported by the local clock and should normally be set to a number high enough to ensure that any other servers available to clients are preferred over this server. + + + general.orphanmode + + checkbox + + general.port text Set the port chrony listen to. + + general.allowednetworks + + + select_multiple + true + Set the networks allowed to synchronize time with this server. If this value is not set it will also not listen to the port and just synchronize the time for itself. + general.ntsclient @@ -23,26 +51,10 @@ checkbox If you run NTS mode you can enable this option in order to ignore wrong time in certificates for the first check. This helps if your system starts with wrong time. - - general.peers - - - select_multiple - true - Set as many NTP peers you need. - general.fallbackpeers text Set fallback peer if you use NTS and your system starts with wrong time. Best to only use this for internal trusted peers. - - general.allowednetworks - - - select_multiple - true - Set the networks allowed to synchronize time with this server. If this value is not set it will also not listen to the port and just synchronize the time for itself. - diff --git a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml index 08d29de0c..ee22171f0 100644 --- a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml +++ b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml @@ -7,10 +7,31 @@ 0 Y + + 0.opnsense.pool.ntp.org + Y + , + Y + + + 1 + 15 + N + Local stratum must be within 1-15. + + + 0 + Y + 323 Y + + N + , + Y + 0 Y @@ -19,19 +40,8 @@ 0 Y - - 0.opnsense.pool.ntp.org - Y - , - Y - N - - N - , - Y - diff --git a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf index 7cd4f7a16..04bd7dbf6 100644 --- a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf +++ b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf @@ -5,32 +5,35 @@ driftfile /var/db/chrony/drift pidfile /var/run/chrony/chronyd.pid makestep 1 3 -{% if helpers.exists('OPNsense.chrony.general.ntsclient') and OPNsense.chrony.general.ntsclient == '1' %} +{% if not helpers.empty('OPNsense.chrony.general.peers') %} +{% for peer in OPNsense.chrony.general.peers.split(',') %} +server {{ peer }} iburst {% if helpers.exists('OPNsense.chrony.general.ntsclient') and OPNsense.chrony.general.ntsclient == '1' %}nts{% endif %} +{% endfor %} +{% endif %} + +{% if helpers.exists('OPNsense.chrony.general.fallbackpeers') and OPNsense.chrony.general.fallbackpeers != '' %} +authselectmode mix +server {{ OPNsense.chrony.general.fallbackpeers }} +{% endif %} + +{% if not helpers.empty('OPNsense.chrony.general.localstratum') %} +local stratum {{ OPNsense.chrony.general.localstratum }} {% if helpers.exists('OPNsense.chrony.general.orphanmode') and OPNsense.chrony.general.orphanmode == '1' %}orphan{% endif %} +{% endif %} + +{% if not helpers.empty('OPNsense.chrony.general.allowednetworks') %} +{% for network in OPNsense.chrony.general.allowednetworks.split(',') %} +allow {{ network }} +{% endfor %} +{% endif %} + +{% if helpers.exists('OPNsense.chrony.general.ntsclient') and OPNsense.chrony.general.ntsclient == '1' %} ntsdumpdir /var/lib/chrony ntstrustedcerts /usr/local/etc/ssl/cert.pem nosystemcert -{% endif %} +{% endif %} -{% if helpers.exists('OPNsense.chrony.general.ntsnocert') and OPNsense.chrony.general.ntsnocert == '1' %} +{% if helpers.exists('OPNsense.chrony.general.ntsnocert') and OPNsense.chrony.general.ntsnocert == '1' %} nocerttimecheck 1 -{% endif %} - -{% if not helpers.empty('OPNsense.chrony.general.peers') %} -{% for peer in OPNsense.chrony.general.peers.split(',') %} -server {{ peer }} iburst {% if helpers.exists('OPNsense.chrony.general.ntsclient') and OPNsense.chrony.general.ntsclient == '1' %}nts{% endif %} - -{% endfor %} -{% endif %} - -{% if helpers.exists('OPNsense.chrony.general.fallbackpeers') and OPNsense.chrony.general.fallbackpeers != '' %} -authselectmode mix -server {{ OPNsense.chrony.general.fallbackpeers }} -{% endif %} - -{% if not helpers.empty('OPNsense.chrony.general.allowednetworks') %} -{% for network in OPNsense.chrony.general.allowednetworks.split(',') %} -allow {{ network }} -{% endfor %} -{% endif %} +{% endif %} {% endif %} From 6dee8c0a3a2b4b847b470ed5fabf5e303909cce9 Mon Sep 17 00:00:00 2001 From: Matthew Otto Date: Mon, 5 Jan 2026 19:23:18 -0600 Subject: [PATCH 05/12] achieve basic functionality with grid --- net/chrony/pkg-descr | 9 ++- .../OPNsense/Chrony/Api/GeneralController.php | 32 +++++++++- ...eralController.php => IndexController.php} | 6 +- .../OPNsense/Chrony/forms/dialogPeer.xml | 64 +++++++++++++++++++ .../OPNsense/Chrony/forms/general.xml | 8 --- .../app/models/OPNsense/Chrony/General.xml | 40 ++++++++++-- .../app/models/OPNsense/Chrony/Menu/Menu.xml | 2 +- .../Chrony/{general.volt => index.volt} | 39 ++++++----- .../templates/OPNsense/Chrony/chrony.conf | 4 +- 9 files changed, 168 insertions(+), 36 deletions(-) rename net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/{GeneralController.php => IndexController.php} (85%) create mode 100644 net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml rename net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/{general.volt => index.volt} (85%) diff --git a/net/chrony/pkg-descr b/net/chrony/pkg-descr index fae71365b..53dafbbc8 100644 --- a/net/chrony/pkg-descr +++ b/net/chrony/pkg-descr @@ -6,7 +6,14 @@ Plugin Changelog 1.6 -* Add NTP data tab +* Update config UI to expose the following features: + - local/orphan mode + - pools + - prefer + - iburst + - min/max poll + - interleaving +* Add NTP data diagnostics 1.5 diff --git a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/Api/GeneralController.php b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/Api/GeneralController.php index d96f5a121..51fb579c0 100644 --- a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/Api/GeneralController.php +++ b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/Api/GeneralController.php @@ -32,6 +32,36 @@ use OPNsense\Base\ApiMutableModelControllerBase; class GeneralController extends ApiMutableModelControllerBase { - protected static $internalModelClass = '\OPNsense\Chrony\General'; protected static $internalModelName = 'general'; + protected static $internalModelClass = '\OPNsense\Chrony\General'; + + public function searchItemAction() + { + return $this->searchBase("peers.peer", null, "address"); + } + + public function setItemAction($uuid) + { + return $this->setBase("peer", "peers.peer", $uuid); + } + + public function addItemAction() + { + return $this->addBase("peer", "peers.peer"); + } + + public function getItemAction($uuid = null) + { + return $this->getBase("peer", "peers.peer", $uuid); + } + + public function delItemAction($uuid) + { + return $this->delBase("peers.peer", $uuid); + } + + public function toggleItemAction($uuid, $enabled = null) + { + return $this->toggleBase("peers.peer", $uuid, $enabled); + } } diff --git a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/GeneralController.php b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/IndexController.php similarity index 85% rename from net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/GeneralController.php rename to net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/IndexController.php index faa214b6a..088f43954 100644 --- a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/GeneralController.php +++ b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/IndexController.php @@ -28,11 +28,13 @@ namespace OPNsense\Chrony; -class GeneralController extends \OPNsense\Base\IndexController +class IndexController extends \OPNsense\Base\IndexController { public function indexAction() { + $this->view->pick('OPNsense/Chrony/index'); $this->view->generalForm = $this->getForm('general'); - $this->view->pick('OPNsense/Chrony/general'); + $this->view->formDialogPeer = $this->getForm("dialogPeer"); + $this->view->formGridPeer = $this->getFormGrid("dialogPeer"); } } diff --git a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml new file mode 100644 index 000000000..66a2bed25 --- /dev/null +++ b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml @@ -0,0 +1,64 @@ +
    + + peer.pool + + checkbox + Address refers to a pool of NTP servers + + 6em + boolean + boolean + + + + peer.address + + text + The address/hostname of the NTP server or pool. + + + peer.iburst + + checkbox + Enable iburst for this source. + + 6em + boolean + boolean + + + + peer.prefer + + checkbox + Prefer this source over sources without the prefer option. + + 6em + boolean + boolean + + + + peer.xleave + + checkbox + Enable interleaved mode for this source. + + 6em + boolean + boolean + + + + general.minpoll + + text + The minimum interval between requests sent to the server as a power of 2 in seconds. + + + general.maxpoll + + text + The maximum interval between requests sent to the server as a power of 2 in seconds. + +
    \ No newline at end of file diff --git a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml index be7d29794..a14a75025 100644 --- a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml +++ b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml @@ -5,14 +5,6 @@ checkbox Enable Chrony time daemon. - - general.peers - - - select_multiple - true - Set as many NTP peers you need. - general.localstratum diff --git a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml index ee22171f0..3367735f9 100644 --- a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml +++ b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml @@ -7,11 +7,41 @@ 0 Y - - 0.opnsense.pool.ntp.org - Y - , - Y + + + + 1 + Y + +
    + opnsense.pool.ntp.org + Y +
    + + 0 + Y + + + 0 + Y + + + 0 + Y + + + -6 + 24 + N + minpoll value must be between -6 and 24. + + + -6 + 24 + N + maxpoll value must be between -6 and 24. + +
    1 diff --git a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/Menu/Menu.xml b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/Menu/Menu.xml index e11f5fe9c..fef1b45bd 100644 --- a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/Menu/Menu.xml +++ b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/Menu/Menu.xml @@ -1,7 +1,7 @@ - + diff --git a/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/general.volt b/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/index.volt similarity index 85% rename from net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/general.volt rename to net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/index.volt index 255c464b3..bd27a5a5f 100644 --- a/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/general.volt +++ b/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/index.volt @@ -38,10 +38,14 @@
    {{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_general_settings'])}} -
    -
    - -
    + +

    {{ lang._('Sources') }}

    + + {{ partial('layout_partials/base_bootgrid_table', formGridPeer) }} + + {{ partial('layout_partials/base_apply_button', {'data_endpoint': '/api/chrony/service/reconfigure'}) }} + + {{ partial("layout_partials/base_dialog",['fields':formDialogPeer,'id':formGridPeer['edit_dialog_id'],'label':lang._('Edit source')])}}
    @@ -62,7 +66,21 @@
    diff --git a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf index 04bd7dbf6..670c2cc95 100644 --- a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf +++ b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf @@ -6,8 +6,8 @@ pidfile /var/run/chrony/chronyd.pid makestep 1 3 {% if not helpers.empty('OPNsense.chrony.general.peers') %} -{% for peer in OPNsense.chrony.general.peers.split(',') %} -server {{ peer }} iburst {% if helpers.exists('OPNsense.chrony.general.ntsclient') and OPNsense.chrony.general.ntsclient == '1' %}nts{% endif %} +{% for peer in OPNsense.chrony.general.peers.peer %} +{% if peer.pool == '1' %}pool {% else %}server {% endif %}{{ peer.address }}{% if peer.prefer == '1' %} prefer{% endif %}{% if peer.iburst == '1' %} iburst{% endif %}{% if peer.xleave == '1' %} xleave{% endif %} {% endfor %} {% endif %} From b3c3ff8c9403a4c226923bd5ea9a51a8ecc7004d Mon Sep 17 00:00:00 2001 From: Matthew Otto Date: Mon, 5 Jan 2026 22:46:50 -0600 Subject: [PATCH 06/12] add minpoll/maxpoll support --- .../OPNsense/Chrony/forms/dialogPeer.xml | 16 ++++++++-------- .../mvc/app/models/OPNsense/Chrony/General.xml | 10 +++++----- .../templates/OPNsense/Chrony/chrony.conf | 3 ++- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml index 66a2bed25..0f2c26151 100644 --- a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml +++ b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml @@ -17,10 +17,10 @@ The address/hostname of the NTP server or pool.
    - peer.iburst - + peer.prefer + checkbox - Enable iburst for this source. + Prefer this source over sources without the prefer option. 6em boolean @@ -28,10 +28,10 @@ - peer.prefer - + peer.iburst + checkbox - Prefer this source over sources without the prefer option. + Enable iburst for this source. 6em boolean @@ -50,13 +50,13 @@ - general.minpoll + peer.minpoll text The minimum interval between requests sent to the server as a power of 2 in seconds. - general.maxpoll + peer.maxpoll text The maximum interval between requests sent to the server as a power of 2 in seconds. diff --git a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml index 3367735f9..eed78dc6f 100644 --- a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml +++ b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml @@ -10,21 +10,21 @@ - 1 + 0 Y
    opnsense.pool.ntp.org Y
    - - 0 - Y - 0 Y + + 0 + Y + 0 Y diff --git a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf index 670c2cc95..0d31e8eb1 100644 --- a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf +++ b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf @@ -7,7 +7,8 @@ makestep 1 3 {% if not helpers.empty('OPNsense.chrony.general.peers') %} {% for peer in OPNsense.chrony.general.peers.peer %} -{% if peer.pool == '1' %}pool {% else %}server {% endif %}{{ peer.address }}{% if peer.prefer == '1' %} prefer{% endif %}{% if peer.iburst == '1' %} iburst{% endif %}{% if peer.xleave == '1' %} xleave{% endif %} +{% if peer.pool == '1' %}pool {% else %}server {% endif %}{{peer.address}}{% if peer.prefer == '1' %} prefer{% endif %}{% if peer.iburst == '1' %} iburst{% endif %}{% if peer.xleave == '1' %} xleave{% endif %}{% if peer.minpoll is defined and peer.minpoll != '' %} minpoll{{ peer.minpoll }}{% endif %}{% if peer.maxpoll is defined and peer.maxpoll != '' %} maxpoll {{ peer.maxpoll }}{% endif %} + {% endfor %} {% endif %} From 4940481d61edf267e6227b1feed31c6e83915905 Mon Sep 17 00:00:00 2001 From: Matthew Otto Date: Mon, 5 Jan 2026 22:50:32 -0600 Subject: [PATCH 07/12] fix minpoll bug --- .../src/opnsense/service/templates/OPNsense/Chrony/chrony.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf index 0d31e8eb1..591d993d1 100644 --- a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf +++ b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf @@ -7,7 +7,7 @@ makestep 1 3 {% if not helpers.empty('OPNsense.chrony.general.peers') %} {% for peer in OPNsense.chrony.general.peers.peer %} -{% if peer.pool == '1' %}pool {% else %}server {% endif %}{{peer.address}}{% if peer.prefer == '1' %} prefer{% endif %}{% if peer.iburst == '1' %} iburst{% endif %}{% if peer.xleave == '1' %} xleave{% endif %}{% if peer.minpoll is defined and peer.minpoll != '' %} minpoll{{ peer.minpoll }}{% endif %}{% if peer.maxpoll is defined and peer.maxpoll != '' %} maxpoll {{ peer.maxpoll }}{% endif %} +{% if peer.pool == '1' %}pool {% else %}server {% endif %}{{peer.address}}{% if peer.prefer == '1' %} prefer{% endif %}{% if peer.iburst == '1' %} iburst{% endif %}{% if peer.xleave == '1' %} xleave{% endif %}{% if peer.minpoll is defined and peer.minpoll != '' %} minpoll {{ peer.minpoll }}{% endif %}{% if peer.maxpoll is defined and peer.maxpoll != '' %} maxpoll {{ peer.maxpoll }}{% endif %} {% endfor %} {% endif %} From 5bb39b1cef542f385602e259bf50385bf341c648 Mon Sep 17 00:00:00 2001 From: Matthew Otto Date: Mon, 5 Jan 2026 23:13:52 -0600 Subject: [PATCH 08/12] replace apply with save (entire config updates now) --- .../mvc/app/views/OPNsense/Chrony/index.volt | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/index.volt b/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/index.volt index bd27a5a5f..998b54351 100644 --- a/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/index.volt +++ b/net/chrony/src/opnsense/mvc/app/views/OPNsense/Chrony/index.volt @@ -43,9 +43,12 @@ {{ partial('layout_partials/base_bootgrid_table', formGridPeer) }} - {{ partial('layout_partials/base_apply_button', {'data_endpoint': '/api/chrony/service/reconfigure'}) }} - {{ partial("layout_partials/base_dialog",['fields':formDialogPeer,'id':formGridPeer['edit_dialog_id'],'label':lang._('Edit source')])}} + +
    +
    + +
    @@ -151,5 +154,16 @@ $(function() { var targetTab = $(e.target).attr("href"); autoRefresh(targetTab); }); + + // link save button to API set action + $("#saveAct").click(function(){ + saveFormToEndpoint(url="/api/chrony/general/set", formid='frm_general_settings',callback_ok=function(){ + $("#saveAct_progress").addClass("fa fa-spinner fa-pulse"); + ajaxCall(url="/api/chrony/service/reconfigure", sendData={}, callback=function(data,status) { + updateServiceControlUI('chrony'); + $("#saveAct_progress").removeClass("fa fa-spinner fa-pulse"); + }); + }); + }); }); From 8fca10855e2a1bf1a7d5a2bf67ff57cf19b2fcb7 Mon Sep 17 00:00:00 2001 From: Matthew Otto Date: Tue, 6 Jan 2026 00:46:52 -0600 Subject: [PATCH 09/12] fix bug when defining only a single source --- .../app/models/OPNsense/Chrony/General.xml | 2 +- .../templates/OPNsense/Chrony/chrony.conf | 22 +++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml index eed78dc6f..897957c01 100644 --- a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml +++ b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml @@ -54,7 +54,7 @@ Y - 323 + 123 Y diff --git a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf index 591d993d1..74ba2732e 100644 --- a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf +++ b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf @@ -1,12 +1,18 @@ {% if helpers.exists('OPNsense.chrony.general.enabled') and OPNsense.chrony.general.enabled == '1' %} port {{ OPNsense.chrony.general.port }} -driftfile /var/db/chrony/drift -pidfile /var/run/chrony/chronyd.pid -makestep 1 3 +{% if not helpers.empty('OPNsense.chrony.general.allowednetworks') %} +{% for network in OPNsense.chrony.general.allowednetworks.split(',') %} +allow {{ network }} +{% endfor %} +{% endif %} {% if not helpers.empty('OPNsense.chrony.general.peers') %} -{% for peer in OPNsense.chrony.general.peers.peer %} +{% set peers = OPNsense.chrony.general.peers.peer %} +{% if peers is mapping %} +{% set peers = [peers] %} +{% endif %} +{% for peer in peers %} {% if peer.pool == '1' %}pool {% else %}server {% endif %}{{peer.address}}{% if peer.prefer == '1' %} prefer{% endif %}{% if peer.iburst == '1' %} iburst{% endif %}{% if peer.xleave == '1' %} xleave{% endif %}{% if peer.minpoll is defined and peer.minpoll != '' %} minpoll {{ peer.minpoll }}{% endif %}{% if peer.maxpoll is defined and peer.maxpoll != '' %} maxpoll {{ peer.maxpoll }}{% endif %} {% endfor %} @@ -19,13 +25,11 @@ server {{ OPNsense.chrony.general.fallbackpeers }} {% if not helpers.empty('OPNsense.chrony.general.localstratum') %} local stratum {{ OPNsense.chrony.general.localstratum }} {% if helpers.exists('OPNsense.chrony.general.orphanmode') and OPNsense.chrony.general.orphanmode == '1' %}orphan{% endif %} -{% endif %} -{% if not helpers.empty('OPNsense.chrony.general.allowednetworks') %} -{% for network in OPNsense.chrony.general.allowednetworks.split(',') %} -allow {{ network }} -{% endfor %} {% endif %} +driftfile /var/db/chrony/drift +pidfile /var/run/chrony/chronyd.pid +makestep 1 3 {% if helpers.exists('OPNsense.chrony.general.ntsclient') and OPNsense.chrony.general.ntsclient == '1' %} ntsdumpdir /var/lib/chrony From 32e8b9e9a5b634ebcc11a3b4a9a5685eb1c2a8f3 Mon Sep 17 00:00:00 2001 From: Matthew Otto Date: Tue, 6 Jan 2026 01:01:48 -0600 Subject: [PATCH 10/12] make diagnostic tabs show column descriptions --- .../src/opnsense/service/conf/actions.d/actions_chrony.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/chrony/src/opnsense/service/conf/actions.d/actions_chrony.conf b/net/chrony/src/opnsense/service/conf/actions.d/actions_chrony.conf index 8d3e6d21a..74c4253f9 100644 --- a/net/chrony/src/opnsense/service/conf/actions.d/actions_chrony.conf +++ b/net/chrony/src/opnsense/service/conf/actions.d/actions_chrony.conf @@ -23,13 +23,13 @@ type:script_output message:request chrony status [chronysources] -command:/usr/local/bin/chronyc -m 'timeout 100' 'retries 0' sources +command:/usr/local/bin/chronyc -m 'timeout 100' 'retries 0' 'sources -v' parameters: type:script_output message:show chrony sources [chronysourcestats] -command:/usr/local/bin/chronyc -m 'timeout 100' 'retries 0' sourcestats +command:/usr/local/bin/chronyc -m 'timeout 100' 'retries 0' 'sourcestats -v' parameters: type:script_output message:show chrony sourcestats @@ -41,7 +41,7 @@ type:script_output message:show chrony tracking [chronyauthdata] -command:/usr/local/bin/chronyc -N -m 'timeout 100' 'retries 0' authdata +command:/usr/local/bin/chronyc -N -m 'timeout 100' 'retries 0' 'authdata -v' parameters: type:script_output message:show chrony authdata From 7043f2d6445558cd0fb904b3941e0e231203d7c0 Mon Sep 17 00:00:00 2001 From: Matthew Otto Date: Tue, 6 Jan 2026 11:08:36 -0600 Subject: [PATCH 11/12] add proper NTS support --- .../OPNsense/Chrony/forms/dialogPeer.xml | 11 ++++ .../OPNsense/Chrony/forms/general.xml | 12 ---- .../app/models/OPNsense/Chrony/General.xml | 57 +++++++++---------- .../templates/OPNsense/Chrony/chrony.conf | 11 +--- 4 files changed, 39 insertions(+), 52 deletions(-) diff --git a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml index 0f2c26151..6e498422a 100644 --- a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml +++ b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/dialogPeer.xml @@ -61,4 +61,15 @@ text The maximum interval between requests sent to the server as a power of 2 in seconds. + + peer.nts + + checkbox + Enable NTS authentication. + + 6em + boolean + boolean + + \ No newline at end of file diff --git a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml index a14a75025..ba5a0ccbe 100644 --- a/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml +++ b/net/chrony/src/opnsense/mvc/app/controllers/OPNsense/Chrony/forms/general.xml @@ -31,22 +31,10 @@ true Set the networks allowed to synchronize time with this server. If this value is not set it will also not listen to the port and just synchronize the time for itself. - - general.ntsclient - - checkbox - Enable NTS in client mode. This will add another layer of security for peers when OPNsense is the client. Every server in Peers has to support NTS. - general.ntsnocert checkbox If you run NTS mode you can enable this option in order to ignore wrong time in certificates for the first check. This helps if your system starts with wrong time. - - general.fallbackpeers - - text - Set fallback peer if you use NTS and your system starts with wrong time. Best to only use this for internal trusted peers. - diff --git a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml index 897957c01..78f763a85 100644 --- a/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml +++ b/net/chrony/src/opnsense/mvc/app/models/OPNsense/Chrony/General.xml @@ -7,6 +7,29 @@ 0 Y + + 1 + 15 + N + Local stratum must be within 1-15. + + + 0 + Y + + + 123 + Y + + + N + , + Y + + + 0 + Y + @@ -41,37 +64,11 @@ N maxpoll value must be between -6 and 24. + + 0 + Y + - - 1 - 15 - N - Local stratum must be within 1-15. - - - 0 - Y - - - 123 - Y - - - N - , - Y - - - 0 - Y - - - 0 - Y - - - N - diff --git a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf index 74ba2732e..364f6ea59 100644 --- a/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf +++ b/net/chrony/src/opnsense/service/templates/OPNsense/Chrony/chrony.conf @@ -13,16 +13,11 @@ allow {{ network }} {% set peers = [peers] %} {% endif %} {% for peer in peers %} -{% if peer.pool == '1' %}pool {% else %}server {% endif %}{{peer.address}}{% if peer.prefer == '1' %} prefer{% endif %}{% if peer.iburst == '1' %} iburst{% endif %}{% if peer.xleave == '1' %} xleave{% endif %}{% if peer.minpoll is defined and peer.minpoll != '' %} minpoll {{ peer.minpoll }}{% endif %}{% if peer.maxpoll is defined and peer.maxpoll != '' %} maxpoll {{ peer.maxpoll }}{% endif %} +{% if peer.pool == '1' %}pool {% else %}server {% endif %}{{peer.address}}{% if peer.prefer == '1' %} prefer{% endif %}{% if peer.iburst == '1' %} iburst{% endif %}{% if peer.xleave == '1' %} xleave{% endif %}{% if peer.minpoll is defined and peer.minpoll != '' %} minpoll {{ peer.minpoll }}{% endif %}{% if peer.maxpoll is defined and peer.maxpoll != '' %} maxpoll {{ peer.maxpoll }}{% endif %}{% if peer.nts == '1' %} nts{% endif %} {% endfor %} {% endif %} -{% if helpers.exists('OPNsense.chrony.general.fallbackpeers') and OPNsense.chrony.general.fallbackpeers != '' %} -authselectmode mix -server {{ OPNsense.chrony.general.fallbackpeers }} -{% endif %} - {% if not helpers.empty('OPNsense.chrony.general.localstratum') %} local stratum {{ OPNsense.chrony.general.localstratum }} {% if helpers.exists('OPNsense.chrony.general.orphanmode') and OPNsense.chrony.general.orphanmode == '1' %}orphan{% endif %} @@ -31,11 +26,7 @@ driftfile /var/db/chrony/drift pidfile /var/run/chrony/chronyd.pid makestep 1 3 -{% if helpers.exists('OPNsense.chrony.general.ntsclient') and OPNsense.chrony.general.ntsclient == '1' %} ntsdumpdir /var/lib/chrony -ntstrustedcerts /usr/local/etc/ssl/cert.pem -nosystemcert -{% endif %} {% if helpers.exists('OPNsense.chrony.general.ntsnocert') and OPNsense.chrony.general.ntsnocert == '1' %} nocerttimecheck 1 From 3f7981faf5bc65804f083edca4e52c09fe36d3a6 Mon Sep 17 00:00:00 2001 From: Matthew Otto Date: Tue, 6 Jan 2026 11:13:52 -0600 Subject: [PATCH 12/12] update pkg-descr --- net/chrony/pkg-descr | 1 + 1 file changed, 1 insertion(+) diff --git a/net/chrony/pkg-descr b/net/chrony/pkg-descr index 53dafbbc8..7c7d2425b 100644 --- a/net/chrony/pkg-descr +++ b/net/chrony/pkg-descr @@ -13,6 +13,7 @@ Plugin Changelog - iburst - min/max poll - interleaving +* Add per-source NTS option * Add NTP data diagnostics 1.5