Project

General

Profile

Download (14 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * status_ntpd.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2024 Rubicon Communications, LLC (Netgate)
9
 * Copyright (c) 2013 Dagorlad
10
 * All rights reserved.
11
 *
12
 * originally based on m0n0wall (http://m0n0.ch/wall)
13
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
14
 * All rights reserved.
15
 *
16
 * Licensed under the Apache License, Version 2.0 (the "License");
17
 * you may not use this file except in compliance with the License.
18
 * You may obtain a copy of the License at
19
 *
20
 * http://www.apache.org/licenses/LICENSE-2.0
21
 *
22
 * Unless required by applicable law or agreed to in writing, software
23
 * distributed under the License is distributed on an "AS IS" BASIS,
24
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25
 * See the License for the specific language governing permissions and
26
 * limitations under the License.
27
 */
28

    
29
##|+PRIV
30
##|*IDENT=page-status-ntp
31
##|*NAME=Status: NTP
32
##|*DESCR=Allow access to the 'Status: NTP' page.
33
##|*MATCH=status_ntpd.php*
34
##|-PRIV
35

    
36
require_once('config.inc');
37
require_once('config.lib.inc');
38
require_once('guiconfig.inc');
39

    
40
$allow_query = !config_path_enabled('ntpd','noquery');
41
foreach (config_get_path('ntpd/restrictions/row', []) as $v) {
42
	if (ip_in_subnet('127.0.0.1', "{$v['acl_network']}/{$v['mask']}") || 
43
		ip_in_subnet('::1', "{$v['acl_network']}/{$v['mask']}")) {
44
		$allow_query = !isset($v['noquery']);
45
	}
46
}
47

    
48
if ($allow_query && (config_get_path('ntpd/enable') != 'disabled')) {
49
	if (config_path_enabled('system','ipv6allow')) {
50
		$inet_version = "";
51
	} else {
52
		$inet_version = " -4";
53
	}
54

    
55
	exec('/usr/local/sbin/ntpq -pnw' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]+/," ")}1\'', $ntpq_output);
56
	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);
57

    
58
	$ntpq_servers = array();
59
	$ntpq_server_responses = array();
60

    
61
	foreach ($ntpq_associations_output as $i => $line) {
62
		$associations_response = array();
63
		$peerinfo = preg_split("/[\s\t]+/", $line);
64
		$server['ind'] = $peerinfo[1];
65
		$associations_response['assid'] = $peerinfo[2];
66
		$associations_response['status_word'] = $peerinfo[3];
67
		$associations_response['conf'] = $peerinfo[4];
68
		$associations_response['reach'] = $peerinfo[5];
69
		$associations_response['auth'] = $peerinfo[6];
70
		$associations_response['condition'] = $peerinfo[7];
71
		$associations_response['last_event'] = $peerinfo[8];
72
		$associations_response['cnt'] = $peerinfo[9];
73
		$ntpq_server_responses[$i] = $associations_response;
74
	}
75

    
76
	foreach ($ntpq_output as $i => $line) {
77
		$server = array();
78
		$status_char = substr($line, 0, 1);
79
		$line = substr($line, 1);
80
		$peerinfo = preg_split("/[\s\t]+/", $line);
81

    
82
		$server['server'] = $peerinfo[0];
83
		$server['refid'] = $peerinfo[1];
84
		$server['stratum'] = $peerinfo[2];
85
		$server['type'] = $peerinfo[3];
86
		$server['when'] = $peerinfo[4];
87
		$server['poll'] = $peerinfo[5];
88
		$server['reach'] = $peerinfo[6];
89
		$server['delay'] = $peerinfo[7];
90
		$server['offset'] = $peerinfo[8];
91
		$server['jitter'] = $peerinfo[9];
92

    
93
		$server['ind'] = $ntpq_server_responses[$i]['ind'];
94
		$server['assid'] = $ntpq_server_responses[$i]['assid'];
95
		$server['status_word'] = $ntpq_server_responses[$i]['status_word'];
96
		$server['conf'] = $ntpq_server_responses[$i]['conf'];
97
		$server['auth'] = $ntpq_server_responses[$i]['auth'];
98
		$server['condition'] = $ntpq_server_responses[$i]['condition'];
99
		$server['last_event'] = $ntpq_server_responses[$i]['last_event'];
100
		$server['cnt'] = $ntpq_server_responses[$i]['cnt'];
101

    
102
		switch ($status_char) {
103
			case " ":
104
				if ($server['refid'] == ".POOL.") {
105
					$server['status'] = gettext("Pool Placeholder");
106
				} else {
107
					$server['status'] = gettext("Unreach/Pending");
108
				}
109
				break;
110
			case "*":
111
				$server['status'] = gettext("Active Peer");
112
				break;
113
			case "+":
114
				$server['status'] = gettext("Candidate");
115
				break;
116
			case "o":
117
				$server['status'] = gettext("PPS Peer");
118
				break;
119
			case "#":
120
				$server['status'] = gettext("Selected");
121
				break;
122
			case ".":
123
				$server['status'] = gettext("Excess Peer");
124
				break;
125
			case "x":
126
				$server['status'] = gettext("False Ticker");
127
				break;
128
			case "-":
129
				$server['status'] = gettext("Outlier");
130
				break;
131
		}
132

    
133
		$ntpq_servers[] = $server;
134
	}
135

    
136
	exec("/usr/local/sbin/ntpq -c clockvar $inet_version", $ntpq_clockvar_output);
137
	foreach ($ntpq_clockvar_output as $line) {
138
		if (substr($line, 0, 9) == "timecode=") {
139
			$tmp = explode('"', $line);
140
			$tmp = $tmp[1];
141
			if (substr($tmp, 0, 6) == '$GPRMC') {
142
				$gps_vars = explode(",", $tmp);
143
				$gps_ok = ($gps_vars[2] == "A");
144
				$gps_lat_deg = substr($gps_vars[3], 0, 2);
145
				$gps_lat_min = substr($gps_vars[3], 2);
146
				$gps_lon_deg = substr($gps_vars[5], 0, 3);
147
				$gps_lon_min = substr($gps_vars[5], 3);
148
				$gps_lat = (float) $gps_lat_deg + (float) $gps_lat_min / 60.0;
149
				$gps_lat = $gps_lat * (($gps_vars[4] == "N") ? 1 : -1);
150
				$gps_lon = (float) $gps_lon_deg + (float) $gps_lon_min / 60.0;
151
				$gps_lon = $gps_lon * (($gps_vars[6] == "E") ? 1 : -1);
152
				$gps_lat_dir = $gps_vars[4];
153
				$gps_lon_dir = $gps_vars[6];
154
			} elseif (substr($tmp, 0, 6) == '$GPGGA') {
155
				$gps_vars = explode(",", $tmp);
156
				$gps_ok = $gps_vars[6];
157
				$gps_lat_deg = substr($gps_vars[2], 0, 2);
158
				$gps_lat_min = substr($gps_vars[2], 2);
159
				$gps_lon_deg = substr($gps_vars[4], 0, 3);
160
				$gps_lon_min = substr($gps_vars[4], 3);
161
				$gps_lat = (float) $gps_lat_deg + (float) $gps_lat_min / 60.0;
162
				$gps_lat = $gps_lat * (($gps_vars[3] == "N") ? 1 : -1);
163
				$gps_lon = (float) $gps_lon_deg + (float) $gps_lon_min / 60.0;
164
				$gps_lon = $gps_lon * (($gps_vars[5] == "E") ? 1 : -1);
165
				$gps_alt = $gps_vars[9];
166
				$gps_alt_unit = $gps_vars[10];
167
				$gps_sat = (int)$gps_vars[7];
168
				$gps_lat_dir = $gps_vars[3];
169
				$gps_lon_dir = $gps_vars[5];
170
			} elseif (substr($tmp, 0, 6) == '$GPGLL') {
171
				$gps_vars = preg_split('/[,\*]+/', $tmp);
172
				$gps_ok = ($gps_vars[6] == "A");
173
				$gps_lat_deg = substr($gps_vars[1], 0, 2);
174
				$gps_lat_min = substr($gps_vars[1], 2);
175
				$gps_lon_deg = substr($gps_vars[3], 0, 3);
176
				$gps_lon_min = substr($gps_vars[3], 3);
177
				$gps_lat = (float) $gps_lat_deg + (float) $gps_lat_min / 60.0;
178
				$gps_lat = $gps_lat * (($gps_vars[2] == "N") ? 1 : -1);
179
				$gps_lon = (float) $gps_lon_deg + (float) $gps_lon_min / 60.0;
180
				$gps_lon = $gps_lon * (($gps_vars[4] == "E") ? 1 : -1);
181
				$gps_lat_dir = $gps_vars[2];
182
				$gps_lon_dir = $gps_vars[4];
183
			} elseif (substr($tmp, 0, 6) == '$PGRMF') {
184
				$gps_vars = preg_split('/[,\*]+/', $tmp);
185
				$gps_ok = $gps_vars[11];
186
				$gps_lat_deg = substr($gps_vars[6], 0, 2);
187
				$gps_lat_min = substr($gps_vars[6], 2);
188
				$gps_lon_deg = substr($gps_vars[8], 0, 3);
189
				$gps_lon_min = substr($gps_vars[8], 3);
190
				$gps_lat = (float) $gps_lat_deg + (float) $gps_lat_min / 60.0;
191
				$gps_lat = $gps_lat * (($gps_vars[7] == "N") ? 1 : -1);
192
				$gps_lon = (float) $gps_lon_deg + (float) $gps_lon_min / 60.0;
193
				$gps_lon = $gps_lon * (($gps_vars[9] == "E") ? 1 : -1);
194
				$gps_lat_dir = $gps_vars[7];
195
				$gps_lon_dir = $gps_vars[9];
196
			}
197
		}
198
	}
199
}
200

    
201
global $showgps;
202
$showgps = 0;
203

    
204
global $gps_goo_lnk;
205
$gps_goo_lnk = 1;
206

    
207
// GPS satellite information (if available)
208
if (($gps_ok) && ($gps_lat) && ($gps_lon)) {
209
	$gps_goo_lnk = 2;
210
	$showgps = 1;
211
}
212

    
213
if (isset($gps_ok) && config_path_enabled('ntpd/gps','extstatus')) {
214
	$lookfor['GPGSV'] = config_path_enabled('ntpd/gps/nmeaset','gpgsv');
215
	$lookfor['GPGGA'] = !isset($gps_sat) && config_path_enabled('ntpd/gps/nmeaset','gpgga');
216
	$gpsport = fopen('/dev/gps0', 'r+');
217
	while ($gpsport && ($lookfor['GPGSV'] || $lookfor['GPGGA'])) {
218
		$buffer = fgets($gpsport);
219
		if ($lookfor['GPGSV'] && substr($buffer, 0, 6) == '$GPGSV') {
220
			$gpgsv = explode(',', $buffer);
221
			$gps_satview = (int)$gpgsv[3];
222
			$lookfor['GPGSV'] = false;
223
		} elseif ($lookfor['GPGGA'] && substr($buffer, 0, 6) == '$GPGGA') {
224
			$gpgga = explode(',', $buffer);
225
			$gps_sat = (int)$gpgga[7];
226
			$gps_alt = $gpgga[9];
227
			$gps_alt_unit = $gpgga[10];
228
			$lookfor['GPGGA'] = false;
229
		}
230
	}
231
}
232

    
233
// Responding to an AJAX call, we return the GPS data or the status data depending on $_REQUEST['dogps']
234
if ($_REQUEST['ajax']) {
235

    
236
	if ($_REQUEST['dogps'] == "yes") {
237
		print_gps();
238
	} else {
239
		print_status();
240
	}
241

    
242
	exit;
243
}
244

    
245
function print_status() {
246
	global $ntpq_servers, $allow_query;
247

    
248
	if (config_get_path('ntpd/enable') == 'disabled'):
249
		print("<tr>\n");
250
		print('<td class="warning" colspan="11">');
251
		printf(gettext('NTP Server is disabled'));
252
		print("</td>\n");
253
		print("</tr>\n");
254
	elseif (!$allow_query):
255
		print("<tr>\n");
256
		print('<td class="warning" colspan="11">');
257
		printf(gettext('Statistics unavailable because ntpq and ntpdc queries are disabled in the %1$sNTP service settings%2$s'), '<a href="services_ntpd.php">', '</a>');
258
		print("</td>\n");
259
		print("</tr>\n");
260
	elseif (count($ntpq_servers) == 0):
261
		print("<tr>\n");
262
		print('<td class="warning" colspan="11">');
263
		printf(gettext('No peers found, %1$sis the ntp service running?%2$s'), '<a href="status_services.php">', '</a>');
264
		print("</td>\n");
265
		print("</tr>\n");
266
	else:
267

    
268
		$i = 0;
269
		foreach ($ntpq_servers as $server):
270
			print("<tr>\n");
271
			print("<td>" . $server['status'] . "</td>\n");
272
			print("<td>" . $server['server'] . "</td>\n");
273
			print("<td>" . $server['refid'] . "</td>\n");
274
			print("<td>" . $server['stratum'] . "</td>\n");
275
			print("<td>" . $server['type'] . "</td>\n");
276
			print("<td>" . $server['when'] . "</td>\n");
277
			print("<td>" . $server['poll'] . "</td>\n");
278
			print("<td>" . $server['reach'] . "</td>\n");
279
			print("<td>" . $server['delay'] . "</td>\n");
280
			print("<td>" . $server['offset'] . "</td>\n");
281
			print("<td>" . $server['jitter'] . "</td>\n");
282
			print("<td>" . $server['assid'] . "</td>\n");
283
			print("<td>" . $server['status_word'] . "</td>\n");
284
			print("<td>" . $server['auth'] . "</td>\n");
285
			print("</tr>\n");
286
			$i++;
287
		endforeach;
288
	endif;
289
}
290

    
291
function print_gps() {
292
	global 	$gps_lat, $gps_lon, $gps_lat_deg, $gps_lon_deg, $gps_lat_min, $gps_lon_min, $gps_lat_dir, $gps_lon_dir,
293
			$gps_alt, $gps_alt_unit, $gps_sat, $gps_satview, $gps_goo_lnk;
294

    
295
	print("<tr>\n");
296
	print("<td>\n");
297
	printf("%.5f", $gps_lat);
298
	print(" (");
299
	printf("%d%s", $gps_lat_deg, "&deg;");
300
	printf("%.5f", $gps_lat_min);
301
	print($gps_lat_dir);
302
	print(")");
303
	print("</td>\n");
304
	print("<td>\n");
305
	printf("%.5f", $gps_lon);
306
	print(" (");
307
	printf("%d%s", $gps_lon_deg, "&deg;");
308
	printf("%.5f", $gps_lon_min);
309
	print($gps_lon_dir);
310
	print(")");
311
	print("</td>\n");
312

    
313
	if (isset($gps_alt)) {
314
		print("<td>\n");
315
		print($gps_alt . ' ' . $gps_alt_unit);
316
		print("</td>\n");
317
	}
318

    
319
	if (isset($gps_sat) || isset($gps_satview)) {
320
		print('<td>');
321

    
322
		if (isset($gps_satview)) {
323
			print(gettext('in view ') . intval($gps_satview));
324
		}
325

    
326
		if (isset($gps_sat) && isset($gps_satview)) {
327
			print(', ');
328
		}
329
		if (isset($gps_sat)) {
330
			print(gettext('in use ') . $gps_sat);
331
		}
332

    
333
		print("</td>\n");
334
	}
335

    
336
	print("</tr>\n");
337
	print("<tr>\n");
338
	print('<td colspan="' . $gps_goo_lnk . '"><a target="_gmaps" href="https://maps.google.com/?q=' . $gps_lat . ',' . $gps_lon . '">' . gettext("Google Maps Link") . '</a></td>');
339
	print("</tr>\n");
340
}
341

    
342
$pgtitle = array(gettext("Status"), gettext("NTP"));
343
$shortcut_section = "ntp";
344

    
345
include("head.inc");
346
?>
347

    
348
<div class="panel panel-default">
349
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Network Time Protocol Status");?></h2></div>
350
	<div class="panel-body table-responsive">
351
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
352
			<thead>
353
				<tr>
354
					<th><?=gettext("Status")?></th>
355
					<th><?=gettext("Server")?></th>
356
					<th><?=gettext("Ref ID")?></th>
357
					<th><?=gettext("Stratum")?></th>
358
					<th><?=gettext("Type")?></th>
359
					<th><?=gettext("When")?></th>
360
					<th><?=gettext("Poll (s)")?></th>
361
					<th><?=gettext("Reach")?></th>
362
					<th><?=gettext("Delay (ms)")?></th>
363
					<th><?=gettext("Offset (ms)")?></th>
364
					<th><?=gettext("Jitter (ms)")?></th>
365
					<th><?=gettext("AssocID")?></th>
366
					<th><?=gettext("Status Word")?></th>
367
					<th><?=gettext("Auth")?></th>
368
				</tr>
369
			</thead>
370
			<tbody id="ntpbody">
371
				<?=print_status()?>
372
			</tbody>
373
		</table>
374
	</div>
375
</div>
376

    
377

    
378
<?php
379

    
380
// GPS satellite information (if available)
381
if (($gps_ok) && ($gps_lat) && ($gps_lon)):
382
	$gps_goo_lnk = 2;
383
	$showgps = 1;
384
?>
385

    
386
<div class="panel panel-default">
387
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("GPS Information");?></h2></div>
388
	<div class="panel-body">
389
		<table class="table table-striped table-hover table-condensed">
390
			<thead>
391
				<tr>
392
					<th><?=gettext("Clock Latitude")?></th>
393
					<th><?=gettext("Clock Longitude")?></th>
394
<?php
395
	if (isset($gps_alt)) {
396
?>
397
					<th><?=gettext("Clock Altitude")?></th>
398
<?php
399
		$gps_goo_lnk++;
400
	}
401

    
402
	if (isset($gps_sat) || isset($gps_satview)) {
403
?>
404
					<th><?=gettext("Satellites")?></th>
405
<?php
406
		$gps_goo_lnk++;
407
	}
408
?>
409
				</tr>
410
			</thead>
411

    
412
			<tbody id="gpsbody">
413
				<?=print_gps()?>
414
			</tbody>
415
		</table>
416
	</div>
417
</div>
418

    
419
<?php
420
endif;
421
?>
422

    
423
<script type="text/javascript">
424
//<![CDATA[
425
events.push(function() {
426
	ajax_lock = false;		// Mutex so we don't make a call until the previous call is finished
427
	do_gps = "no";
428

    
429
	// Fetch the tbody contents from the server
430
	function update_tables() {
431

    
432
		if (ajax_lock) {
433
			return;
434
		}
435

    
436
		ajax_lock = true;
437

    
438
		ajaxRequest = $.ajax(
439
			{
440
				url: "/status_ntpd.php",
441
				type: "post",
442
				data: {
443
					ajax: 	"ajax",
444
					dogps:  do_gps
445
				}
446
			}
447
		);
448

    
449
		// Deal with the results of the above ajax call
450
		ajaxRequest.done(function (response, textStatus, jqXHR) {
451
			if (do_gps == "yes") {
452
				$('#gpsbody').html(response);
453
			} else {
454
				$('#ntpbody').html(response);
455
			}
456

    
457
			ajax_lock = false;
458

    
459
			// Alternate updating the status table and the gps table (if enabled)
460
			if ((do_gps == "yes") || ("<?=$showgps?>" != 1)) {
461
				do_gps = "no";
462
			} else {
463
				do_gps = "yes";
464
			}
465

    
466
			// and do it again
467
			setTimeout(update_tables, 5000);
468
		});
469

    
470

    
471
	}
472

    
473
	// Populate the tbody on page load
474
	update_tables();
475
});
476
//]]>
477
</script>
478

    
479
<?php
480
include("foot.inc");
481
?>
(181-181/232)