Project

General

Profile

Download (12.2 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-2022 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

    
57
	$ntpq_servers = array();
58
	foreach ($ntpq_output as $line) {
59
		$server = array();
60
		$status_char = substr($line, 0, 1);
61
		$line = substr($line, 1);
62
		$peerinfo = preg_split("/[\s\t]+/", $line);
63

    
64
		$server['server'] = $peerinfo[0];
65
		$server['refid'] = $peerinfo[1];
66
		$server['stratum'] = $peerinfo[2];
67
		$server['type'] = $peerinfo[3];
68
		$server['when'] = $peerinfo[4];
69
		$server['poll'] = $peerinfo[5];
70
		$server['reach'] = $peerinfo[6];
71
		$server['delay'] = $peerinfo[7];
72
		$server['offset'] = $peerinfo[8];
73
		$server['jitter'] = $peerinfo[9];
74

    
75
		switch ($status_char) {
76
			case " ":
77
				if ($server['refid'] == ".POOL.") {
78
					$server['status'] = gettext("Pool Placeholder");
79
				} else {
80
					$server['status'] = gettext("Unreach/Pending");
81
				}
82
				break;
83
			case "*":
84
				$server['status'] = gettext("Active Peer");
85
				break;
86
			case "+":
87
				$server['status'] = gettext("Candidate");
88
				break;
89
			case "o":
90
				$server['status'] = gettext("PPS Peer");
91
				break;
92
			case "#":
93
				$server['status'] = gettext("Selected");
94
				break;
95
			case ".":
96
				$server['status'] = gettext("Excess Peer");
97
				break;
98
			case "x":
99
				$server['status'] = gettext("False Ticker");
100
				break;
101
			case "-":
102
				$server['status'] = gettext("Outlier");
103
				break;
104
		}
105

    
106
		$ntpq_servers[] = $server;
107
	}
108

    
109
	exec("/usr/local/sbin/ntpq -c clockvar $inet_version", $ntpq_clockvar_output);
110
	foreach ($ntpq_clockvar_output as $line) {
111
		if (substr($line, 0, 9) == "timecode=") {
112
			$tmp = explode('"', $line);
113
			$tmp = $tmp[1];
114
			if (substr($tmp, 0, 6) == '$GPRMC') {
115
				$gps_vars = explode(",", $tmp);
116
				$gps_ok = ($gps_vars[2] == "A");
117
				$gps_lat_deg = substr($gps_vars[3], 0, 2);
118
				$gps_lat_min = substr($gps_vars[3], 2);
119
				$gps_lon_deg = substr($gps_vars[5], 0, 3);
120
				$gps_lon_min = substr($gps_vars[5], 3);
121
				$gps_lat = (float) $gps_lat_deg + $gps_lat_min / 60.0;
122
				$gps_lat = $gps_lat * (($gps_vars[4] == "N") ? 1 : -1);
123
				$gps_lon = (float) $gps_lon_deg + $gps_lon_min / 60.0;
124
				$gps_lon = $gps_lon * (($gps_vars[6] == "E") ? 1 : -1);
125
				$gps_lat_dir = $gps_vars[4];
126
				$gps_lon_dir = $gps_vars[6];
127
			} elseif (substr($tmp, 0, 6) == '$GPGGA') {
128
				$gps_vars = explode(",", $tmp);
129
				$gps_ok = $gps_vars[6];
130
				$gps_lat_deg = substr($gps_vars[2], 0, 2);
131
				$gps_lat_min = substr($gps_vars[2], 2);
132
				$gps_lon_deg = substr($gps_vars[4], 0, 3);
133
				$gps_lon_min = substr($gps_vars[4], 3);
134
				$gps_lat = (float) $gps_lat_deg + $gps_lat_min / 60.0;
135
				$gps_lat = $gps_lat * (($gps_vars[3] == "N") ? 1 : -1);
136
				$gps_lon = (float) $gps_lon_deg + $gps_lon_min / 60.0;
137
				$gps_lon = $gps_lon * (($gps_vars[5] == "E") ? 1 : -1);
138
				$gps_alt = $gps_vars[9];
139
				$gps_alt_unit = $gps_vars[10];
140
				$gps_sat = (int)$gps_vars[7];
141
				$gps_lat_dir = $gps_vars[3];
142
				$gps_lon_dir = $gps_vars[5];
143
			} elseif (substr($tmp, 0, 6) == '$GPGLL') {
144
				$gps_vars = preg_split('/[,\*]+/', $tmp);
145
				$gps_ok = ($gps_vars[6] == "A");
146
				$gps_lat_deg = substr($gps_vars[1], 0, 2);
147
				$gps_lat_min = substr($gps_vars[1], 2);
148
				$gps_lon_deg = substr($gps_vars[3], 0, 3);
149
				$gps_lon_min = substr($gps_vars[3], 3);
150
				$gps_lat = (float) $gps_lat_deg + $gps_lat_min / 60.0;
151
				$gps_lat = $gps_lat * (($gps_vars[2] == "N") ? 1 : -1);
152
				$gps_lon = (float) $gps_lon_deg + $gps_lon_min / 60.0;
153
				$gps_lon = $gps_lon * (($gps_vars[4] == "E") ? 1 : -1);
154
				$gps_lat_dir = $gps_vars[2];
155
				$gps_lon_dir = $gps_vars[4];
156
			} elseif (substr($tmp, 0, 6) == '$PGRMF') {
157
				$gps_vars = preg_split('/[,\*]+/', $tmp);
158
				$gps_ok = $gps_vars[11];
159
				$gps_lat_deg = substr($gps_vars[6], 0, 2);
160
				$gps_lat_min = substr($gps_vars[6], 2);
161
				$gps_lon_deg = substr($gps_vars[8], 0, 3);
162
				$gps_lon_min = substr($gps_vars[8], 3);
163
				$gps_lat = (float) $gps_lat_deg + $gps_lat_min / 60.0;
164
				$gps_lat = $gps_lat * (($gps_vars[7] == "N") ? 1 : -1);
165
				$gps_lon = (float) $gps_lon_deg + $gps_lon_min / 60.0;
166
				$gps_lon = $gps_lon * (($gps_vars[9] == "E") ? 1 : -1);
167
				$gps_lat_dir = $gps_vars[7];
168
				$gps_lon_dir = $gps_vars[9];
169
			}
170
		}
171
	}
172
}
173

    
174
if (isset($gps_ok) && config_path_enabled('ntpd/gps','extstatus') &&
175
	(config_path_enabled('ntpd/gps/nmeaset','gpgsv') ||
176
	 config_path_enabled('ntpd/gps/nmeaset','gpgga'))) {
177
	$lookfor['GPGSV'] = config_path_enabled('ntpd/gps/nmeaset','gpgsv');
178
	$lookfor['GPGGA'] = !isset($gps_sat) && config_path_enabled('ntpd/gps/nmeaset','gpgga');
179
	$gpsport = fopen('/dev/gps0', 'r+');
180
	while ($gpsport && ($lookfor['GPGSV'] || $lookfor['GPGGA'])) {
181
		$buffer = fgets($gpsport);
182
		if ($lookfor['GPGSV'] && substr($buffer, 0, 6) == '$GPGSV') {
183
			$gpgsv = explode(',', $buffer);
184
			$gps_satview = (int)$gpgsv[3];
185
			$lookfor['GPGSV'] = false;
186
		} elseif ($lookfor['GPGGA'] && substr($buffer, 0, 6) == '$GPGGA') {
187
			$gpgga = explode(',', $buffer);
188
			$gps_sat = (int)$gpgga[7];
189
			$gps_alt = $gpgga[9];
190
			$gps_alt_unit = $gpgga[10];
191
			$lookfor['GPGGA'] = false;
192
		}
193
	}
194
}
195

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

    
199
	if ($_REQUEST['dogps'] == "yes") {
200
		print_gps();
201
	} else {
202
		print_status();
203
	}
204

    
205
	exit;
206
}
207

    
208
function print_status() {
209
	global $ntpq_servers, $allow_query;
210

    
211
	if (config_get_path('ntpd/enable') == 'disabled'):
212
		print("<tr>\n");
213
		print('<td class="warning" colspan="11">');
214
		printf(gettext('NTP Server is disabled'));
215
		print("</td>\n");
216
		print("</tr>\n");
217
	elseif (!$allow_query):
218
		print("<tr>\n");
219
		print('<td class="warning" colspan="11">');
220
		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>');
221
		print("</td>\n");
222
		print("</tr>\n");
223
	elseif (count($ntpq_servers) == 0):
224
		print("<tr>\n");
225
		print('<td class="warning" colspan="11">');
226
		printf(gettext('No peers found, %1$sis the ntp service running?%2$s'), '<a href="status_services.php">', '</a>');
227
		print("</td>\n");
228
		print("</tr>\n");
229
	else:
230

    
231
		$i = 0;
232
		foreach ($ntpq_servers as $server):
233
			print("<tr>\n");
234
			print("<td>" . $server['status'] . "</td>\n");
235
			print("<td>" . $server['server'] . "</td>\n");
236
			print("<td>" . $server['refid'] . "</td>\n");
237
			print("<td>" . $server['stratum'] . "</td>\n");
238
			print("<td>" . $server['type'] . "</td>\n");
239
			print("<td>" . $server['when'] . "</td>\n");
240
			print("<td>" . $server['poll'] . "</td>\n");
241
			print("<td>" . $server['reach'] . "</td>\n");
242
			print("<td>" . $server['delay'] . "</td>\n");
243
			print("<td>" . $server['offset'] . "</td>\n");
244
			print("<td>" . $server['jitter'] . "</td>\n");
245
			print("</tr>\n");
246
			$i++;
247
		endforeach;
248
	endif;
249
}
250

    
251
function print_gps() {
252
	global 	$gps_lat, $gps_lon, $gps_lat_deg, $gps_lon_deg, $gps_lat_min, $gps_lon_min, $gps_lat_dir, $gps_lon_dir,
253
			$gps_alt, $gps_alt_unit, $gps_sat, $gps_satview, $gps_goo_lnk;
254

    
255
	print("<tr>\n");
256
	print("<td>\n");
257
	printf("%.5f", $gps_lat);
258
	print(" (");
259
	printf("%d%s", $gps_lat_deg, "&deg;");
260
	printf("%.5f", $gps_lat_min);
261
	print($gps_lat_dir);
262
	print(")");
263
	print("</td>\n");
264
	print("<td>\n");
265
	printf("%.5f", $gps_lon);
266
	print(" (");
267
	printf("%d%s", $gps_lon_deg, "&deg;");
268
	printf("%.5f", $gps_lon_min);
269
	print($gps_lon_dir);
270
	print(")");
271
	print("</td>\n");
272

    
273
	if (isset($gps_alt)) {
274
		print("<td>\n");
275
		print($gps_alt . ' ' . $gps_alt_unit);
276
		print("</td>\n");
277
	}
278

    
279
	if (isset($gps_sat) || isset($gps_satview)) {
280
		print('<td>');
281

    
282
		if (isset($gps_satview)) {
283
			print(gettext('in view ') . intval($gps_satview));
284
		}
285

    
286
		if (isset($gps_sat) && isset($gps_satview)) {
287
			print(', ');
288
		}
289
		if (isset($gps_sat)) {
290
			print(gettext('in use ') . $gps_sat);
291
		}
292

    
293
		print("</td>\n");
294
	}
295

    
296
	print("</tr>\n");
297
	print("<tr>\n");
298
	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>');
299
	print("</tr>\n");
300
}
301

    
302
$pgtitle = array(gettext("Status"), gettext("NTP"));
303
$shortcut_section = "ntp";
304

    
305
include("head.inc");
306
?>
307

    
308
<div class="panel panel-default">
309
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Network Time Protocol Status");?></h2></div>
310
	<div class="panel-body">
311
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
312
			<thead>
313
				<tr>
314
					<th><?=gettext("Status")?></th>
315
					<th><?=gettext("Server")?></th>
316
					<th><?=gettext("Ref ID")?></th>
317
					<th><?=gettext("Stratum")?></th>
318
					<th><?=gettext("Type")?></th>
319
					<th><?=gettext("When")?></th>
320
					<th><?=gettext("Poll (s)")?></th>
321
					<th><?=gettext("Reach")?></th>
322
					<th><?=gettext("Delay (ms)")?></th>
323
					<th><?=gettext("Offset (ms)")?></th>
324
					<th><?=gettext("Jitter (ms)")?></th>
325
				</tr>
326
			</thead>
327
			<tbody id="ntpbody">
328
				<?=print_status()?>
329
			</tbody>
330
		</table>
331
	</div>
332
</div>
333

    
334

    
335
<?php
336

    
337
$showgps = 0;
338

    
339
// GPS satellite information (if available)
340
if (($gps_ok) && ($gps_lat) && ($gps_lon)):
341
	$gps_goo_lnk = 2;
342
	$showgps = 1;
343
?>
344

    
345
<div class="panel panel-default">
346
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("GPS Information");?></h2></div>
347
	<div class="panel-body">
348
		<table class="table table-striped table-hover table-condensed">
349
			<thead>
350
				<tr>
351
					<th><?=gettext("Clock Latitude")?></th>
352
					<th><?=gettext("Clock Longitude")?></th>
353
<?php
354
	if (isset($gps_alt)) {
355
?>
356
					<th><?=gettext("Clock Altitude")?></th>
357
<?php
358
		$gps_goo_lnk++;
359
	}
360

    
361
	if (isset($gps_sat) || isset($gps_satview)) {
362
?>
363
					<th><?=gettext("Satellites")?></th>
364
<?php
365
		$gps_goo_lnk++;
366
	}
367
?>
368
				</tr>
369
			</thead>
370

    
371
			<tbody id="gpsbody">
372
				<?=print_gps()?>
373
			</tbody>
374
		</table>
375
	</div>
376
</div>
377

    
378
<?php
379
endif;
380
?>
381

    
382
<script type="text/javascript">
383
//<![CDATA[
384
events.push(function() {
385
	ajax_lock = false;		// Mutex so we don't make a call until the previous call is finished
386
	do_gps = "no";
387

    
388
	// Fetch the tbody contents from the server
389
	function update_tables() {
390

    
391
		if (ajax_lock) {
392
			return;
393
		}
394

    
395
		ajax_lock = true;
396

    
397
		ajaxRequest = $.ajax(
398
			{
399
				url: "/status_ntpd.php",
400
				type: "post",
401
				data: {
402
					ajax: 	"ajax",
403
					dogps:  do_gps
404
				}
405
			}
406
		);
407

    
408
		// Deal with the results of the above ajax call
409
		ajaxRequest.done(function (response, textStatus, jqXHR) {
410
			if (do_gps == "yes") {
411
				$('#gpsbody').html(response);
412
			} else {
413
				$('#ntpbody').html(response);
414
			}
415

    
416
			ajax_lock = false;
417

    
418
			// Alternate updating the status table and the gps table (if enabled)
419
			if ((do_gps == "yes") || ("<?=$showgps?>" != 1)) {
420
				do_gps = "no";
421
			} else {
422
				do_gps = "yes";
423
			}
424

    
425
			// and do it again
426
			setTimeout(update_tables, 5000);
427
		});
428

    
429

    
430
	}
431

    
432
	// Populate the tbody on page load
433
	update_tables();
434
});
435
//]]>
436
</script>
437

    
438
<?php
439
include("foot.inc");
440
?>
(177-177/228)