Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NTP authentication Feature #8794 #4658

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

MatthewA1
Copy link

Implements #8794
Adds NTP Key ID field to NTP Services page
Adds NTP Authentication status to NTP Status page
@MatthewA1
Copy link
Author

This is my first time contribution to pfSense, so please do thoroughly review. I applied these patches to a pfSense CE 2.7.1 instance and tested with an authenticated NTP server using MD5 and everything seemed to work.
I based my work on the patches posted by LamaZ on the original ticket, so thank you LamaZ.
The only problem I see is with the formatting of the table on the NTP Status page as the table is wider than the table header.

@JonathanDLee24
Copy link

I have tested this in pfSense Plus and it works.
Screenshot 2023-12-05 at 8 12 05 PM

Screenshot 2023-12-05 at 8 24 30 PM

@JonathanDLee24
Copy link

I had to strip off /src for pfSense plus tested with 23.05.01

@marcos-ng
Copy link
Collaborator

marcos-ng commented Dec 12, 2023

There are multiple issues around NTP which need to be resolved. I think the page needs some refactoring to fix those issues and to better implement authentication. I've added notes on the redmine regarding the issues. As for this specific MR, I don't think we'll merge this until further consideration to the issues in the redmine is given, as well as implementing server-specific keys.

Still, here's a patch with some revisions to the MR (note that I have not tested this myself).

diff --git a/src/etc/inc/system.inc b/src/etc/inc/system.inc
index 33d674d9ff..1a2d2d2f1b 100644
--- a/src/etc/inc/system.inc
+++ b/src/etc/inc/system.inc
@@ -2327,6 +2327,7 @@ function system_ntp_configure() {
 	$driftfile = "/var/db/ntpd.drift";
 	$statsdir = "/var/log/ntp";
 	$gps_device = '/dev/gps0';
+	$ntp_keyid = config_get_path('ntpd/serverauthkeyid') ?? '1';
 
 	safe_mkdir($statsdir);
 
@@ -2356,7 +2357,7 @@ function system_ntp_configure() {
 
 	/* set NTP server authentication key */
 	if (config_get_path('ntpd/serverauth') == 'yes') {
-		$ntpkeyscfg = "1 " . strtoupper(config_get_path('ntpd/serverauthalgo')) . " " . base64_decode(config_get_path('ntpd/serverauthkey')) . "\n";
+		$ntpkeyscfg = "{$ntp_keyid} " . strtoupper(config_get_path('ntpd/serverauthalgo')) . " " . base64_decode(config_get_path('ntpd/serverauthkey')) . "\n";
 		if (!@file_put_contents("{$g['varetc_path']}/ntp.keys", $ntpkeyscfg)) {
 			log_error(sprintf(gettext("Could not open %s/ntp.keys for writing"), g_get('varetc_path')));
 			return;
@@ -2373,9 +2374,9 @@ function system_ntp_configure() {
 	if (config_get_path('ntpd/serverauth') == 'yes') {
 		$ntpcfg .= "# Authentication settings \n";
 		$ntpcfg .= "keys /var/etc/ntp.keys \n";
-		$ntpcfg .= "trustedkey 1 \n";
-		$ntpcfg .= "requestkey 1 \n";
-		$ntpcfg .= "controlkey 1 \n";
+		$ntpcfg .= "trustedkey {$ntp_keyid} \n";
+		$ntpcfg .= "requestkey {$ntp_keyid} \n";
+		$ntpcfg .= "controlkey {$ntp_keyid} \n";
 		$ntpcfg .= "\n";
 	}
 
@@ -2552,6 +2553,9 @@ function system_ntp_configure() {
 		if (substr_count(config_get_path('ntpd/noselect'), $ts)) {
 			$ntpcfg .= ' noselect';
 		}
+		if (config_get_path('ntpd/serverauth') == 'yes'/* && !substr_count(config_get_path('ntpd/ispool'), $ts)*/) {
+			$ntpcfg .= " key {$ntp_keyid} ";
+		}
 		$ntpcfg .= "\n";
 	}
 	unset($ts);
diff --git a/src/usr/local/www/services_ntpd.php b/src/usr/local/www/services_ntpd.php
index 6fd495ff2f..6d655ecea3 100644
--- a/src/usr/local/www/services_ntpd.php
+++ b/src/usr/local/www/services_ntpd.php
@@ -99,6 +99,12 @@ if ($_POST) {
 	if (isset($pconfig['serverauth'])) {
 		if (empty($pconfig['serverauthkey'])) {
 			$input_errors[] = gettext("The supplied value for NTP Authentication key can't be empty.");
+		} elseif (empty($pconfig['serverauthkeyid'])) {
+			$input_errors[] = gettext("The authentication Key ID can't be empty.");
+		} elseif (!ctype_digit($pconfig['serverauthkeyid'])) {
+			$input_errors[] = gettext("The authentication Key ID must be a positive integer.");
+		} elseif ($pconfig['serverauthkeyid'] < 1 || $pconfig['serverauthkeyid'] > 65535) {
+			$input_errors[] = gettext("The authentication Key ID must be between 1-65535.");
 		} elseif (($pconfig['serverauthalgo'] == 'md5') && ((strlen($pconfig['serverauthkey']) > 20) ||
 		    !ctype_print($pconfig['serverauthkey']))) {
 			$input_errors[] = gettext("The supplied value for NTP Authentication key for MD5 digest must be from 1 to 20 printable characters.");
@@ -212,10 +218,12 @@ if ($_POST) {
 		if (!empty($_POST['serverauth'])) {
 			config_set_path('ntpd/serverauth', $_POST['serverauth']);
 			config_set_path('ntpd/serverauthkey', base64_encode(trim($_POST['serverauthkey'])));
+			config_set_path('ntpd/serverauthkeyid', $_POST['serverauthkeyid']);
 			config_set_path('ntpd/serverauthalgo', $_POST['serverauthalgo']);
 		} elseif (isset($config['ntpd']['serverauth'])) {
 			config_del_path('ntpd/serverauth');
 			config_del_path('ntpd/serverauthkey');
+			config_del_path('ntpd/serverauthkeyid');
 			config_del_path('ntpd/serverauthalgo');
 		}
 
@@ -540,9 +548,18 @@ $section->addInput(new Form_Checkbox(
 $group = new Form_Group('Authentication key');
 $group->addClass('ntpserverauth');
 
-$group->add(new Form_IpAddress(
+$group->add(new Form_Input(
+	'serverauthkeyid',
+	'Key ID',
+	null,
+	$pconfig['serverauthkeyid'],
+	['type' => 'number', 'min' => 1, 'max' => 65535, 'step' => 1]
+))->setWidth(2)->setHelp('ID associated with the authentication key');
+
+$group->add(new Form_Input(
 	'serverauthkey',
 	'NTP Authentication key',
+	'text',
 	base64_decode($pconfig['serverauthkey']),
 	['placeholder' => 'NTP Authentication key']
 ))->setHelp(
@@ -557,7 +574,7 @@ $group->add(new Form_Select(
 	null,
 	$pconfig['serverauthalgo'],
 	$ntp_auth_halgos
-))->setWidth(3)->setHelp('Digest algorithm');
+))->setWidth(2)->setHelp('Digest algorithm');
 
 $section->add($group);
 
diff --git a/src/usr/local/www/status_ntpd.php b/src/usr/local/www/status_ntpd.php
index 0475344d2c..2887edb293 100644
--- a/src/usr/local/www/status_ntpd.php
+++ b/src/usr/local/www/status_ntpd.php
@@ -52,10 +52,28 @@ if ($allow_query && (config_get_path('ntpd/enable') != 'disabled')) {
 		$inet_version = " -4";
 	}
 
-	exec('/usr/local/sbin/ntpq -pnw ' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]+/," ")}1\'', $ntpq_output);
+	exec('/usr/local/sbin/ntpq -pnw' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]+/," ")}1\'', $ntpq_output);
+	exec('/usr/local/sbin/ntpq -c associations' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]\n+/," ")}1\'', $ntpq_associations_output);
 
 	$ntpq_servers = array();
-	foreach ($ntpq_output as $line) {
+	$ntpq_server_responses = array();
+
+	foreach ($ntpq_associations_output as $i => $line) {
+		$associations_response = array();
+		$peerinfo = preg_split("/[\s\t]+/", $line);
+		$server['ind'] = $peerinfo[1];
+		$associations_response['assid'] = $peerinfo[2];
+		$associations_response['status_word'] = $peerinfo[3];
+		$associations_response['conf'] = $peerinfo[4];
+		$associations_response['reach'] = $peerinfo[5];
+		$associations_response['auth'] = $peerinfo[6];
+		$associations_response['condition'] = $peerinfo[7];
+		$associations_response['last_event'] = $peerinfo[8];
+		$associations_response['cnt'] = $peerinfo[9];
+		$ntpq_server_responses[$i] = $associations_response;
+	}
+
+	foreach ($ntpq_output as $i => $line) {
 		$server = array();
 		$status_char = substr($line, 0, 1);
 		$line = substr($line, 1);
@@ -72,6 +90,15 @@ if ($allow_query && (config_get_path('ntpd/enable') != 'disabled')) {
 		$server['offset'] = $peerinfo[8];
 		$server['jitter'] = $peerinfo[9];
 
+		$server['ind'] = $ntpq_server_responses[$i]['ind'];
+		$server['assid'] = $ntpq_server_responses[$i]['assid'];
+		$server['status_word'] = $ntpq_server_responses[$i]['status_word'];
+		$server['conf'] = $ntpq_server_responses[$i]['conf'];
+		$server['auth'] = $ntpq_server_responses[$i]['auth'];
+		$server['condition'] = $ntpq_server_responses[$i]['condition'];
+		$server['last_event'] = $ntpq_server_responses[$i]['last_event'];
+		$server['cnt'] = $ntpq_server_responses[$i]['cnt'];
+
 		switch ($status_char) {
 			case " ":
 				if ($server['refid'] == ".POOL.") {
@@ -252,6 +279,9 @@ function print_status() {
 			print("<td>" . $server['delay'] . "</td>\n");
 			print("<td>" . $server['offset'] . "</td>\n");
 			print("<td>" . $server['jitter'] . "</td>\n");
+			print("<td>" . $server['assid'] . "</td>\n");
+			print("<td>" . $server['status_word'] . "</td>\n");
+			print("<td>" . $server['auth'] . "</td>\n");
 			print("</tr>\n");
 			$i++;
 		endforeach;
@@ -332,6 +362,9 @@ include("head.inc");
 					<th><?=gettext("Delay (ms)")?></th>
 					<th><?=gettext("Offset (ms)")?></th>
 					<th><?=gettext("Jitter (ms)")?></th>
+					<th><?=gettext("AssocID")?></th>
+					<th><?=gettext("Status Word")?></th>
+					<th><?=gettext("Auth")?></th>
 				</tr>
 			</thead>
 			<tbody id="ntpbody">

@JonathanDLee24
Copy link

@marcos-ng your patch worked. I also just attempted the patch with commit id in it named "Incorporated changes from @marcos-ng" that @MatthewA1 added and it would not debug for some reason however.

Marcos-ng I was able to just copy paste yours in and it works GUI option appears and it's functional for pfSense plus.

Screenshot 2024-01-01 at 11 14 11 AM Screenshot 2024-01-01 at 11 13 40 AM Screenshot 2024-01-01 at 11 14 52 AM Screenshot 2024-01-01 at 11 15 22 AM

Testing with 847e417 This fails when I use the github commit ID however when testing this for fetch patch.

Screenshot 2024-01-01 at 11 18 24 AM Screenshot 2024-01-01 at 11 17 34 AM

@JonathanDLee24
Copy link

JonathanDLee24 commented Jan 1, 2024

This is what is pulled with the commit id

From 847e417b5612f28bc1e84ca028a980df9c5c57a7 Mon Sep 17 00:00:00 2001
From: MatthewA1 <22651099+MatthewA1@users.noreply.github.com>
Date: Wed, 13 Dec 2023 21:47:15 -0600
Subject: [PATCH] Incorporated changes from @marcos-ng

---
 src/etc/inc/system.inc              | 17 +++++++----------
 src/usr/local/www/services_ntpd.php | 16 ++++++++--------
 src/usr/local/www/status_ntpd.php   | 13 ++++---------
 3 files changed, 19 insertions(+), 27 deletions(-)

diff --git a/src/etc/inc/system.inc b/src/etc/inc/system.inc
index 3edbf2e8f77..1a2d2d2f1b8 100644
--- a/src/etc/inc/system.inc
+++ b/src/etc/inc/system.inc
@@ -2327,7 +2327,7 @@ function system_ntp_configure() {
 	$driftfile = "/var/db/ntpd.drift";
 	$statsdir = "/var/log/ntp";
 	$gps_device = '/dev/gps0';
-	$ntp_key = "1";
+	$ntp_keyid = config_get_path('ntpd/serverauthkeyid') ?? '1';
 
 	safe_mkdir($statsdir);
 
@@ -2357,10 +2357,7 @@ function system_ntp_configure() {
 
 	/* set NTP server authentication key */
 	if (config_get_path('ntpd/serverauth') == 'yes') {
-		if (config_get_path('ntpd/serverauthkeyid') !== null) {
-			$ntp_key = config_get_path('ntpd/serverauthkeyid');
-		}
-		$ntpkeyscfg = $ntp_key . " " . strtoupper(config_get_path('ntpd/serverauthalgo')) . " " . base64_decode(config_get_path('ntpd/serverauthkey')) . "\n";
+		$ntpkeyscfg = "{$ntp_keyid} " . strtoupper(config_get_path('ntpd/serverauthalgo')) . " " . base64_decode(config_get_path('ntpd/serverauthkey')) . "\n";
 		if (!@file_put_contents("{$g['varetc_path']}/ntp.keys", $ntpkeyscfg)) {
 			log_error(sprintf(gettext("Could not open %s/ntp.keys for writing"), g_get('varetc_path')));
 			return;
@@ -2377,9 +2374,9 @@ function system_ntp_configure() {
 	if (config_get_path('ntpd/serverauth') == 'yes') {
 		$ntpcfg .= "# Authentication settings \n";
 		$ntpcfg .= "keys /var/etc/ntp.keys \n";
-		$ntpcfg .= "trustedkey " . $ntp_key . " \n";
-		$ntpcfg .= "requestkey " . $ntp_key . " \n";
-		$ntpcfg .= "controlkey " . $ntp_key . " \n";
+		$ntpcfg .= "trustedkey {$ntp_keyid} \n";
+		$ntpcfg .= "requestkey {$ntp_keyid} \n";
+		$ntpcfg .= "controlkey {$ntp_keyid} \n";
 		$ntpcfg .= "\n";
 	}
 
@@ -2556,8 +2553,8 @@ function system_ntp_configure() {
 		if (substr_count(config_get_path('ntpd/noselect'), $ts)) {
 			$ntpcfg .= ' noselect';
 		}
-		if (config_get_path('ntpd/serverauth') == 'yes') {
-			$ntpcfg .= " key " . $ntp_key . " ";
+		if (config_get_path('ntpd/serverauth') == 'yes' && !substr_count(config_get_path('ntpd/ispool'), $ts)) {
+			$ntpcfg .= " key {$ntp_keyid} ";
 		}
 		$ntpcfg .= "\n";
 	}
diff --git a/src/usr/local/www/services_ntpd.php b/src/usr/local/www/services_ntpd.php
index 64411c47515..14bef2e8c1d 100644
--- a/src/usr/local/www/services_ntpd.php
+++ b/src/usr/local/www/services_ntpd.php
@@ -100,9 +100,11 @@
 		if (empty($pconfig['serverauthkey'])) {
 			$input_errors[] = gettext("The supplied value for NTP Authentication key can't be empty.");
 		} elseif (empty($pconfig['serverauthkeyid'])) {
-			$input_errors[] = gettext("The supplied value for NTP Authentication key number can't be empty");
+			$input_errors[] = gettext("The authentication Key ID can't be empty.");
 		} elseif (!ctype_digit($pconfig['serverauthkeyid'])) {
-			$input_errors[] = gettext("The supplied value for NTP Authentication key number must be a positive integer");
+			$input_errors[] = gettext("The authentication Key ID must be a positive integer.");
+		} elseif ($pconfig['serverauthkeyid'] < 1 || $pconfig['serverauthkeyid'] > 65535) {
+			$input_errors[] = gettext("The authentication Key ID must be between 1-65535.");
 		} elseif (($pconfig['serverauthalgo'] == 'md5') && ((strlen($pconfig['serverauthkey']) > 20) ||
 		    !ctype_print($pconfig['serverauthkey']))) {
 			$input_errors[] = gettext("The supplied value for NTP Authentication key for MD5 digest must be from 1 to 20 printable characters.");
@@ -548,13 +550,11 @@ function build_interface_list() {
 
 $group->add(new Form_Input(
 	'serverauthkeyid',
-	'NTP Authentication key number',
-	'number',
+	'Key ID',
+	null,
 	$pconfig['serverauthkeyid'],
-	['placeholder' => 'NTP Authentication key ID', 'min' => '0', 'max' => '4,294,967,295']
-))->setWidth(2)->setHelp(
-	'Key ID associated with the NTP Authentication key'
-);
+	['placeholder' => 'Key ID', 'type' => 'number', 'min' => 1, 'max' => 65535, 'step' => 1]
+))->setWidth(2)->setHelp('ID associated with the authentication key');
 
 $group->add(new Form_Input(
 	'serverauthkey',
diff --git a/src/usr/local/www/status_ntpd.php b/src/usr/local/www/status_ntpd.php
index 688501dd25c..2887edb293e 100644
--- a/src/usr/local/www/status_ntpd.php
+++ b/src/usr/local/www/status_ntpd.php
@@ -57,8 +57,8 @@
 
 	$ntpq_servers = array();
 	$ntpq_server_responses = array();
-	$i = 0;
-	foreach ($ntpq_associations_output as $line) {
+
+	foreach ($ntpq_associations_output as $i => $line) {
 		$associations_response = array();
 		$peerinfo = preg_split("/[\s\t]+/", $line);
 		$server['ind'] = $peerinfo[1];
@@ -70,14 +70,10 @@
 		$associations_response['condition'] = $peerinfo[7];
 		$associations_response['last_event'] = $peerinfo[8];
 		$associations_response['cnt'] = $peerinfo[9];
-
 		$ntpq_server_responses[$i] = $associations_response;
-		$i = $i +1;
 	}
 
-	$i = 0;
-
-	foreach ($ntpq_output as $line) {
+	foreach ($ntpq_output as $i => $line) {
 		$server = array();
 		$status_char = substr($line, 0, 1);
 		$line = substr($line, 1);
@@ -135,7 +131,6 @@
 		}
 
 		$ntpq_servers[] = $server;
-		$i = $i + 1;
 	}
 
 	exec("/usr/local/sbin/ntpq -c clockvar $inet_version", $ntpq_clockvar_output);
@@ -248,7 +243,7 @@
 }
 
 function print_status() {
-	global $ntpq_servers, $allow_query, $ntpq_server_responses;
+	global $ntpq_servers, $allow_query;
 
 	if (config_get_path('ntpd/enable') == 'disabled'):
 		print("<tr>\n");

@JonathanDLee24
Copy link

JonathanDLee24 commented Jan 1, 2024

This is Marcos patch that worked

diff --git a/src/etc/inc/system.inc b/src/etc/inc/system.inc
index 33d674d9ff..1a2d2d2f1b 100644
--- a/src/etc/inc/system.inc
+++ b/src/etc/inc/system.inc
@@ -2327,6 +2327,7 @@ function system_ntp_configure() {
 	$driftfile = "/var/db/ntpd.drift";
 	$statsdir = "/var/log/ntp";
 	$gps_device = '/dev/gps0';
+	$ntp_keyid = config_get_path('ntpd/serverauthkeyid') ?? '1';
 
 	safe_mkdir($statsdir);
 
@@ -2356,7 +2357,7 @@ function system_ntp_configure() {
 
 	/* set NTP server authentication key */
 	if (config_get_path('ntpd/serverauth') == 'yes') {
-		$ntpkeyscfg = "1 " . strtoupper(config_get_path('ntpd/serverauthalgo')) . " " . base64_decode(config_get_path('ntpd/serverauthkey')) . "\n";
+		$ntpkeyscfg = "{$ntp_keyid} " . strtoupper(config_get_path('ntpd/serverauthalgo')) . " " . base64_decode(config_get_path('ntpd/serverauthkey')) . "\n";
 		if (!@file_put_contents("{$g['varetc_path']}/ntp.keys", $ntpkeyscfg)) {
 			log_error(sprintf(gettext("Could not open %s/ntp.keys for writing"), g_get('varetc_path')));
 			return;
@@ -2373,9 +2374,9 @@ function system_ntp_configure() {
 	if (config_get_path('ntpd/serverauth') == 'yes') {
 		$ntpcfg .= "# Authentication settings \n";
 		$ntpcfg .= "keys /var/etc/ntp.keys \n";
-		$ntpcfg .= "trustedkey 1 \n";
-		$ntpcfg .= "requestkey 1 \n";
-		$ntpcfg .= "controlkey 1 \n";
+		$ntpcfg .= "trustedkey {$ntp_keyid} \n";
+		$ntpcfg .= "requestkey {$ntp_keyid} \n";
+		$ntpcfg .= "controlkey {$ntp_keyid} \n";
 		$ntpcfg .= "\n";
 	}
 
@@ -2552,6 +2553,9 @@ function system_ntp_configure() {
 		if (substr_count(config_get_path('ntpd/noselect'), $ts)) {
 			$ntpcfg .= ' noselect';
 		}
+		if (config_get_path('ntpd/serverauth') == 'yes'/* && !substr_count(config_get_path('ntpd/ispool'), $ts)*/) {
+			$ntpcfg .= " key {$ntp_keyid} ";
+		}
 		$ntpcfg .= "\n";
 	}
 	unset($ts);
diff --git a/src/usr/local/www/services_ntpd.php b/src/usr/local/www/services_ntpd.php
index 6fd495ff2f..6d655ecea3 100644
--- a/src/usr/local/www/services_ntpd.php
+++ b/src/usr/local/www/services_ntpd.php
@@ -99,6 +99,12 @@ if ($_POST) {
 	if (isset($pconfig['serverauth'])) {
 		if (empty($pconfig['serverauthkey'])) {
 			$input_errors[] = gettext("The supplied value for NTP Authentication key can't be empty.");
+		} elseif (empty($pconfig['serverauthkeyid'])) {
+			$input_errors[] = gettext("The authentication Key ID can't be empty.");
+		} elseif (!ctype_digit($pconfig['serverauthkeyid'])) {
+			$input_errors[] = gettext("The authentication Key ID must be a positive integer.");
+		} elseif ($pconfig['serverauthkeyid'] < 1 || $pconfig['serverauthkeyid'] > 65535) {
+			$input_errors[] = gettext("The authentication Key ID must be between 1-65535.");
 		} elseif (($pconfig['serverauthalgo'] == 'md5') && ((strlen($pconfig['serverauthkey']) > 20) ||
 		    !ctype_print($pconfig['serverauthkey']))) {
 			$input_errors[] = gettext("The supplied value for NTP Authentication key for MD5 digest must be from 1 to 20 printable characters.");
@@ -212,10 +218,12 @@ if ($_POST) {
 		if (!empty($_POST['serverauth'])) {
 			config_set_path('ntpd/serverauth', $_POST['serverauth']);
 			config_set_path('ntpd/serverauthkey', base64_encode(trim($_POST['serverauthkey'])));
+			config_set_path('ntpd/serverauthkeyid', $_POST['serverauthkeyid']);
 			config_set_path('ntpd/serverauthalgo', $_POST['serverauthalgo']);
 		} elseif (isset($config['ntpd']['serverauth'])) {
 			config_del_path('ntpd/serverauth');
 			config_del_path('ntpd/serverauthkey');
+			config_del_path('ntpd/serverauthkeyid');
 			config_del_path('ntpd/serverauthalgo');
 		}
 
@@ -540,9 +548,18 @@ $section->addInput(new Form_Checkbox(
 $group = new Form_Group('Authentication key');
 $group->addClass('ntpserverauth');
 
-$group->add(new Form_IpAddress(
+$group->add(new Form_Input(
+	'serverauthkeyid',
+	'Key ID',
+	null,
+	$pconfig['serverauthkeyid'],
+	['type' => 'number', 'min' => 1, 'max' => 65535, 'step' => 1]
+))->setWidth(2)->setHelp('ID associated with the authentication key');
+
+$group->add(new Form_Input(
 	'serverauthkey',
 	'NTP Authentication key',
+	'text',
 	base64_decode($pconfig['serverauthkey']),
 	['placeholder' => 'NTP Authentication key']
 ))->setHelp(
@@ -557,7 +574,7 @@ $group->add(new Form_Select(
 	null,
 	$pconfig['serverauthalgo'],
 	$ntp_auth_halgos
-))->setWidth(3)->setHelp('Digest algorithm');
+))->setWidth(2)->setHelp('Digest algorithm');
 
 $section->add($group);
 
diff --git a/src/usr/local/www/status_ntpd.php b/src/usr/local/www/status_ntpd.php
index 0475344d2c..2887edb293 100644
--- a/src/usr/local/www/status_ntpd.php
+++ b/src/usr/local/www/status_ntpd.php
@@ -52,10 +52,28 @@ if ($allow_query && (config_get_path('ntpd/enable') != 'disabled')) {
 		$inet_version = " -4";
 	}
 
-	exec('/usr/local/sbin/ntpq -pnw ' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]+/," ")}1\'', $ntpq_output);
+	exec('/usr/local/sbin/ntpq -pnw' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]+/," ")}1\'', $ntpq_output);
+	exec('/usr/local/sbin/ntpq -c associations' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]\n+/," ")}1\'', $ntpq_associations_output);
 
 	$ntpq_servers = array();
-	foreach ($ntpq_output as $line) {
+	$ntpq_server_responses = array();
+
+	foreach ($ntpq_associations_output as $i => $line) {
+		$associations_response = array();
+		$peerinfo = preg_split("/[\s\t]+/", $line);
+		$server['ind'] = $peerinfo[1];
+		$associations_response['assid'] = $peerinfo[2];
+		$associations_response['status_word'] = $peerinfo[3];
+		$associations_response['conf'] = $peerinfo[4];
+		$associations_response['reach'] = $peerinfo[5];
+		$associations_response['auth'] = $peerinfo[6];
+		$associations_response['condition'] = $peerinfo[7];
+		$associations_response['last_event'] = $peerinfo[8];
+		$associations_response['cnt'] = $peerinfo[9];
+		$ntpq_server_responses[$i] = $associations_response;
+	}
+
+	foreach ($ntpq_output as $i => $line) {
 		$server = array();
 		$status_char = substr($line, 0, 1);
 		$line = substr($line, 1);
@@ -72,6 +90,15 @@ if ($allow_query && (config_get_path('ntpd/enable') != 'disabled')) {
 		$server['offset'] = $peerinfo[8];
 		$server['jitter'] = $peerinfo[9];
 
+		$server['ind'] = $ntpq_server_responses[$i]['ind'];
+		$server['assid'] = $ntpq_server_responses[$i]['assid'];
+		$server['status_word'] = $ntpq_server_responses[$i]['status_word'];
+		$server['conf'] = $ntpq_server_responses[$i]['conf'];
+		$server['auth'] = $ntpq_server_responses[$i]['auth'];
+		$server['condition'] = $ntpq_server_responses[$i]['condition'];
+		$server['last_event'] = $ntpq_server_responses[$i]['last_event'];
+		$server['cnt'] = $ntpq_server_responses[$i]['cnt'];
+
 		switch ($status_char) {
 			case " ":
 				if ($server['refid'] == ".POOL.") {
@@ -252,6 +279,9 @@ function print_status() {
 			print("<td>" . $server['delay'] . "</td>\n");
 			print("<td>" . $server['offset'] . "</td>\n");
 			print("<td>" . $server['jitter'] . "</td>\n");
+			print("<td>" . $server['assid'] . "</td>\n");
+			print("<td>" . $server['status_word'] . "</td>\n");
+			print("<td>" . $server['auth'] . "</td>\n");
 			print("</tr>\n");
 			$i++;
 		endforeach;
@@ -332,6 +362,9 @@ include("head.inc");
 					<th><?=gettext("Delay (ms)")?></th>
 					<th><?=gettext("Offset (ms)")?></th>
 					<th><?=gettext("Jitter (ms)")?></th>
+					<th><?=gettext("AssocID")?></th>
+					<th><?=gettext("Status Word")?></th>
+					<th><?=gettext("Auth")?></th>
 				</tr>
 			</thead>
 			<tbody id="ntpbody">

@JonathanDLee24
Copy link

Side Note:

Original https://redmine.pfsense.org/users/38059 Lamaz patch here.

--- /etc/inc/system.inc.orig.23.01	2023-02-20 11:07:17.000586000 -0500
+++ /etc/inc/system.inc	2023-02-20 20:05:49.538823000 -0500
@@ -1828,6 +1828,7 @@
 	$driftfile = "/var/db/ntpd.drift";
 	$statsdir = "/var/log/ntp";
 	$gps_device = '/dev/gps0';
+	$ntp_key = "1";
 
 	safe_mkdir($statsdir);
 
@@ -1857,7 +1858,8 @@
 
 	/* set NTP server authentication key */
 	if (config_get_path('ntpd/serverauth') == 'yes') {
-		$ntpkeyscfg = "1 " . strtoupper(config_get_path('ntpd/serverauthalgo')) . " " . base64_decode(config_get_path('ntpd/serverauthkey')) . "\n";
+		$ntp_key = "23302";
+		$ntpkeyscfg = $ntp_key . " " . strtoupper(config_get_path('ntpd/serverauthalgo')) . " " . base64_decode(config_get_path('ntpd/serverauthkey')) . "\n";
 		if (!@file_put_contents("{$g['varetc_path']}/ntp.keys", $ntpkeyscfg)) {
 			log_error(sprintf(gettext("Could not open %s/ntp.keys for writing"), g_get('varetc_path')));
 			return;
@@ -1874,9 +1876,9 @@
 	if (config_get_path('ntpd/serverauth') == 'yes') {
 		$ntpcfg .= "# Authentication settings \n";
 		$ntpcfg .= "keys /var/etc/ntp.keys \n";
-		$ntpcfg .= "trustedkey 1 \n";
-		$ntpcfg .= "requestkey 1 \n";
-		$ntpcfg .= "controlkey 1 \n";
+		$ntpcfg .= "trustedkey " . $ntp_key . " \n";
+		$ntpcfg .= "requestkey " . $ntp_key . " \n";
+		$ntpcfg .= "controlkey " . $ntp_key . " \n";
 		$ntpcfg .= "\n";
 	}
 
@@ -2049,6 +2051,9 @@
 		}
 		if (substr_count(config_get_path('ntpd/noselect'), $ts)) {
 			$ntpcfg .= ' noselect';
+		}
+		if (config_get_path('ntpd/serverauth') == 'yes') {
+			$ntpcfg .= " key " . $ntp_key . " ";
 		}
 		$ntpcfg .= "\n";
 	}

Second part

--- status_ntpd.php.original	2023-02-24 16:03:19.967717000 -0500
+++ /usr/local/www/status_ntpd.php	2023-02-25 07:37:38.947966000 -0500
@@ -52,9 +52,33 @@
 		$inet_version = " -4";
 	}
 
-	exec('/usr/local/sbin/ntpq -pnw ' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]+/," ")}1\'', $ntpq_output);
+	exec('/usr/local/sbin/ntpq -pnw' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]+/," ")}1\'', $ntpq_output);
+	exec('/usr/local/sbin/ntpq -c associations' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]\n+/," ")}1\'', $ntpq_associations_output);
 
 	$ntpq_servers = array();
+	$ntpq_server_responses = array();
+	$i = 0;
+	foreach ($ntpq_associations_output as $line) {
+		$associations_response = array();
+                $peerinfo = preg_split("/[\s\t]+/", $line);
+		
+		$server['ind'] = $peerinfo[1];
+                $associations_response['assid'] = $peerinfo[2];
+                $associations_response['status_word'] = $peerinfo[3];
+                $associations_response['conf'] = $peerinfo[4];
+		$associations_response['reach'] = $peerinfo[5];
+                $associations_response['auth'] = $peerinfo[6];
+		$associations_response['condition'] = $peerinfo[7];
+                $associations_response['last_event'] = $peerinfo[8];
+                $associations_response['cnt'] = $peerinfo[9];
+
+
+		$ntpq_server_responses[$i] = $associations_response;
+		$i = $i +1;
+	}
+	
+	$i = 0;
+
 	foreach ($ntpq_output as $line) {
 		$server = array();
 		$status_char = substr($line, 0, 1);
@@ -72,6 +96,16 @@
 		$server['offset'] = $peerinfo[8];
 		$server['jitter'] = $peerinfo[9];
 
+                $server['ind'] = $ntpq_server_responses[$i]['ind'];
+                $server['assid'] = $ntpq_server_responses[$i]['assid'];
+                $server['status_word'] = $ntpq_server_responses[$i]['status_word'];
+                $server['conf'] = $ntpq_server_responses[$i]['conf'];
+                $server['auth'] = $ntpq_server_responses[$i]['auth'];
+                $server['condition'] = $ntpq_server_responses[$i]['condition'];
+                $server['last_event'] = $ntpq_server_responses[$i]['last_event'];
+                $server['cnt'] = $ntpq_server_responses[$i]['cnt'];
+
+ 
 		switch ($status_char) {
 			case " ":
 				if ($server['refid'] == ".POOL.") {
@@ -104,6 +138,7 @@
 		}
 
 		$ntpq_servers[] = $server;
+		$i = $i + 1;
 	}
 
 	exec("/usr/local/sbin/ntpq -c clockvar $inet_version", $ntpq_clockvar_output);
@@ -206,7 +241,7 @@
 }
 
 function print_status() {
-	global $ntpq_servers, $allow_query;
+	global $ntpq_servers, $allow_query, $ntpq_server_responses;
 
 	if (config_get_path('ntpd/enable') == 'disabled'):
 		print("<tr>\n");
@@ -242,6 +277,9 @@
 			print("<td>" . $server['delay'] . "</td>\n");
 			print("<td>" . $server['offset'] . "</td>\n");
 			print("<td>" . $server['jitter'] . "</td>\n");
+                        print("<td>" . $server['assid'] . "</td>\n");
+                        print("<td>" . $server['status_word'] . "</td>\n");
+                        print("<td>" . $server['auth'] . "</td>\n");
 			print("</tr>\n");
 			$i++;
 		endforeach;
@@ -322,6 +360,9 @@
 					<th><?=gettext("Delay (ms)")?></th>
 					<th><?=gettext("Offset (ms)")?></th>
 					<th><?=gettext("Jitter (ms)")?></th>
+                                        <th><?=gettext("AssocID")?></th>
+                                        <th><?=gettext("Status Word")?></th>
+                                        <th><?=gettext("Auth")?></th>
 				</tr>
 			</thead>
 			<tbody id="ntpbody">

@MatthewA1
Copy link
Author

@marcos-ng Could I get some feedback on this PR? It still has the changes requested label applied, but I think I've made the requested changes for the minimum viable feature. If additional changes are still needed, or there is someone else I need to mention, please let me know.
I posted some additional thoughts on the Redmine ticket (8794), but I'd like to see this completion of the basic feature get merged for the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants