Project

General

Profile

Download (13 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * status_graph.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Electric Sheep Fencing, LLC
7
 * All rights reserved.
8
 *
9
 * originally based on m0n0wall (http://m0n0.ch/wall)
10
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
11
 * All rights reserved.
12
 *
13
 * Redistribution and use in source and binary forms, with or without
14
 * modification, are permitted provided that the following conditions are met:
15
 *
16
 * 1. Redistributions of source code must retain the above copyright notice,
17
 *    this list of conditions and the following disclaimer.
18
 *
19
 * 2. Redistributions in binary form must reproduce the above copyright
20
 *    notice, this list of conditions and the following disclaimer in
21
 *    the documentation and/or other materials provided with the
22
 *    distribution.
23
 *
24
 * 3. All advertising materials mentioning features or use of this software
25
 *    must display the following acknowledgment:
26
 *    "This product includes software developed by the pfSense Project
27
 *    for use in the pfSense® software distribution. (http://www.pfsense.org/).
28
 *
29
 * 4. The names "pfSense" and "pfSense Project" must not be used to
30
 *    endorse or promote products derived from this software without
31
 *    prior written permission. For written permission, please contact
32
 *    coreteam@pfsense.org.
33
 *
34
 * 5. Products derived from this software may not be called "pfSense"
35
 *    nor may "pfSense" appear in their names without prior written
36
 *    permission of the Electric Sheep Fencing, LLC.
37
 *
38
 * 6. Redistributions of any form whatsoever must retain the following
39
 *    acknowledgment:
40
 *
41
 * "This product includes software developed by the pfSense Project
42
 * for use in the pfSense software distribution (http://www.pfsense.org/).
43
 *
44
 * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
45
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
48
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
51
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55
 * OF THE POSSIBILITY OF SUCH DAMAGE.
56
 */
57

    
58
##|+PRIV
59
##|*IDENT=page-status-trafficgraph
60
##|*NAME=Status: Traffic Graph
61
##|*DESCR=Allow access to the 'Status: Traffic Graph' page.
62
##|*MATCH=status_graph.php*
63
##|*MATCH=bandwidth_by_ip.php*
64
##|*MATCH=graph.php*
65
##|*MATCH=ifstats.php*
66
##|-PRIV
67

    
68
require_once("guiconfig.inc");
69
require_once("ipsec.inc");
70

    
71
// Get configured interface list
72
$ifdescrs = get_configured_interface_with_descr();
73
if (ipsec_enabled()) {
74
	$ifdescrs['enc0'] = gettext("IPsec");
75
}
76

    
77
foreach (array('server', 'client') as $mode) {
78
	if (is_array($config['openvpn']["openvpn-{$mode}"])) {
79
		foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
80
			if (!isset($setting['disable'])) {
81
				$ifdescrs['ovpn' . substr($mode, 0, 1) . $setting['vpnid']] = gettext("OpenVPN") . " " . $mode . ": ".htmlspecialchars($setting['description']);
82
			}
83
		}
84
	}
85
}
86

    
87
// Compatiblity to restore GET parameters used pre-2.3
88
// Useful to save a URL for a given graph configuration
89
if (isset($_GET['if']) && !isset($_POST['if'])) {
90
	$_POST['if'] = $_GET['if'];
91
}
92
if (isset($_GET['sort']) && !isset($_POST['sort'])) {
93
	$_POST['sort'] = $_GET['sort'];
94
}
95
if (isset($_GET['filter']) && !isset($_POST['filter'])) {
96
	$_POST['filter'] = $_GET['filter'];
97
}
98
if (isset($_GET['hostipformat']) && !isset($_POST['hostipformat'])) {
99
	$_POST['hostipformat'] = $_GET['hostipformat'];
100
}
101

    
102
if ($_POST['if']) {
103
	$curif = $_POST['if'];
104
	$found = false;
105
	foreach ($ifdescrs as $descr => $ifdescr) {
106
		if ($descr == $curif) {
107
			$found = true;
108
			break;
109
		}
110
	}
111
	if ($found === false) {
112
		header("Location: status_graph.php");
113
		exit;
114
	}
115
} else {
116
	if (empty($ifdescrs["wan"])) {
117
		/* Handle the case when WAN has been disabled. Use the first key in ifdescrs. */
118
		reset($ifdescrs);
119
		$curif = key($ifdescrs);
120
	} else {
121
		$curif = "wan";
122
	}
123
}
124
if ($_POST['sort']) {
125
	$cursort = $_POST['sort'];
126
} else {
127
	$cursort = "";
128
}
129
if ($_POST['filter']) {
130
	$curfilter = $_POST['filter'];
131
} else {
132
	$curfilter = "";
133
}
134
if ($_POST['hostipformat']) {
135
	$curhostipformat = $_POST['hostipformat'];
136
} else {
137
	$curhostipformat = "";
138
}
139

    
140
function iflist() {
141
	global $ifdescrs;
142

    
143
	$iflist = array();
144

    
145
	foreach ($ifdescrs as $ifn => $ifd) {
146
		$iflist[$ifn] = $ifd;
147
	}
148

    
149
	return($iflist);
150
}
151

    
152
$pgtitle = array(gettext("Status"), gettext("Traffic Graph"));
153

    
154
include("head.inc");
155

    
156
$form = new Form(false);
157
$form->addClass('auto-submit');
158

    
159
$section = new Form_Section('Graph Settings');
160

    
161
$group = new Form_Group('');
162

    
163
$group->add(new Form_Select(
164
	'if',
165
	null,
166
	$curif,
167
	iflist()
168
))->setHelp('Interface');
169

    
170
$group->add(new Form_Select(
171
	'sort',
172
	null,
173
	$cursort,
174
	array (
175
		'in'	=> gettext('Bandwidth In'),
176
		'out'	=> gettext('Bandwidth Out')
177
	)
178
))->setHelp('Sort by');
179

    
180
$group->add(new Form_Select(
181
	'filter',
182
	null,
183
	$curfilter,
184
	array (
185
		'local'	=> gettext('Local'),
186
		'remote'=> gettext('Remote'),
187
		'all'	=> gettext('All')
188
	)
189
))->setHelp('Filter');
190

    
191
$group->add(new Form_Select(
192
	'hostipformat',
193
	null,
194
	$curhostipformat,
195
	array (
196
		''			=> gettext('IP Address'),
197
		'hostname'	=> gettext('Host Name'),
198
		'descr'		=> gettext('Description'),
199
		'fqdn'		=> gettext('FQDN')
200
	)
201
))->setHelp('Display');
202

    
203
$section->add($group);
204

    
205
$form->add($section);
206
print $form;
207

    
208
?>
209

    
210
<script src="/vendor/d3/d3.min.js"></script>
211
<script src="/vendor/nvd3/nv.d3.js"></script>
212
<script src="/vendor/visibility/visibility-1.2.3.min.js"></script>
213

    
214
<link href="/vendor/nvd3/nv.d3.css" media="screen, projection" rel="stylesheet" type="text/css">
215

    
216
<script type="text/javascript">
217

    
218
//<![CDATA[
219
events.push(function() {
220

    
221
	var InterfaceString = "<?=$curif?>";
222

    
223
	//store saved settings in a fresh localstorage
224
	localStorage.clear();
225
	localStorage.setItem('interfaces', JSON.stringify(InterfaceString.split("|"))); //TODO see if can be switched to interfaces
226
	localStorage.setItem('interval', 1);
227
	localStorage.setItem('invert', "true");
228
	localStorage.setItem('size', 1);
229

    
230
	window.charts = {};
231
    window.myData = {};
232
    window.updateIds = 0;
233
    window.latest = [];
234
    var refreshInterval = localStorage.getItem('interval');
235

    
236
    //TODO make it fall on a second value so it increments better
237
    var now = then = new Date(Date.now());
238

    
239
    var nowTime = now.getTime();
240

    
241
	$.each( JSON.parse(localStorage.getItem('interfaces')), function( key, value ) {
242

    
243
		myData[value] = [];
244
		updateIds = 0;
245

    
246
		var itemIn = new Object();
247
		var itemOut = new Object();
248

    
249
		itemIn.key = value + " (in)";
250
		if(localStorage.getItem('invert') === "true") { itemIn.area = true; }
251
		itemIn.first = true;
252
		itemIn.values = [{x: nowTime, y: 0}];
253
		myData[value].push(itemIn);
254

    
255
		itemOut.key = value + " (out)";
256
		if(localStorage.getItem('invert') === "true") { itemOut.area = true; }
257
		itemOut.first = true;
258
		itemOut.values = [{x: nowTime, y: 0}];
259
		myData[value].push(itemOut);
260

    
261
	});
262

    
263
	draw_graph(refreshInterval, then);
264

    
265
	//re-draw graph when the page goes from inactive (in it's window) to active
266
	Visibility.change(function (e, state) {
267
		if(state === "visible") {
268

    
269
			now = then = new Date(Date.now());
270

    
271
			var nowTime = now.getTime();
272

    
273
			$.each( JSON.parse(localStorage.getItem('interfaces')), function( key, value ) {
274

    
275
				Visibility.stop(updateIds);
276

    
277
				myData[value] = [];
278

    
279
				var itemIn = new Object();
280
				var itemOut = new Object();
281

    
282
				itemIn.key = value + " (in)";
283
				if(localStorage.getItem('invert') === "true") { itemIn.area = true; }
284
				itemIn.first = true;
285
				itemIn.values = [{x: nowTime, y: 0}];
286
				myData[value].push(itemIn);
287

    
288
				itemOut.key = value + " (out)";
289
				if(localStorage.getItem('invert') === "true") { itemOut.area = true; }
290
				itemOut.first = true;
291
				itemOut.values = [{x: nowTime, y: 0}];
292
				myData[value].push(itemOut);
293

    
294
			});
295

    
296
			draw_graph(refreshInterval, then);
297

    
298
		}
299
	});
300

    
301
	// save new config defaults
302
    $( '#traffic-graph-form' ).submit(function(event) {
303

    
304
		var error = false;
305
		$("#traffic-chart-error").hide();
306

    
307
		var interfaces = $( "#traffic-graph-interfaces" ).val();
308
		refreshInterval = parseInt($( "#traffic-graph-interval" ).val());
309
		var invert = $( "#traffic-graph-invert" ).val();
310
		var size = $( "#traffic-graph-size" ).val();
311

    
312
		//TODO validate interfaces data and throw error
313

    
314
		if(!Number.isInteger(refreshInterval) || refreshInterval < 1 || refreshInterval > 10) {
315
			error = 'Refresh Interval is not a valid number between 1 and 10.';
316
		}
317

    
318
		if(invert != "true" && invert != "false") {
319

    
320
			error = 'Invert is not a boolean of true or false.';
321

    
322
		}
323

    
324
		if(!error) {
325

    
326
			var formData = {
327
				'traffic-graph-interfaces' : interfaces,
328
				'traffic-graph-interval'   : refreshInterval,
329
				'traffic-graph-invert'     : invert,
330
				'traffic-graph-size'       : size
331
			};
332

    
333
			$.ajax({
334
				type        : 'POST',
335
				url         : '/widgets/widgets/traffic_graphs.widget.php',
336
				data        : formData,
337
				dataType    : 'json',
338
				encode      : true
339
			})
340
			.done(function(message) {
341

    
342
				if(message.success) {
343

    
344
					Visibility.stop(updateIds);
345

    
346
					//remove all old graphs (divs/svgs)
347
					$( ".traffic-widget-chart" ).remove();
348

    
349
					localStorage.setItem('interfaces', JSON.stringify(interfaces));
350
					localStorage.setItem('interval', refreshInterval);
351
					localStorage.setItem('invert', invert);
352
					localStorage.setItem('size', size);
353

    
354
					//redraw graph with new settings
355
					now = then = new Date(Date.now());
356

    
357
					var freshData = [];
358

    
359
					var nowTime = now.getTime();
360

    
361
					$.each( interfaces, function( key, value ) {
362

    
363
						//create new graphs (divs/svgs)
364
						$("#widget-traffic_graphs_panel-body").append('<div id="traffic-chart-' + value + '" class="d3-chart traffic-widget-chart"><svg></svg></div>');
365

    
366
						myData[value] = [];
367

    
368
						var itemIn = new Object();
369
						var itemOut = new Object();
370

    
371
						itemIn.key = value + " (in)";
372
						if(localStorage.getItem('invert') === "true") { itemIn.area = true; }
373
						itemIn.first = true;
374
						itemIn.values = [{x: nowTime, y: 0}];
375
						myData[value].push(itemIn);
376

    
377
						itemOut.key = value + " (out)";
378
						if(localStorage.getItem('invert') === "true") { itemOut.area = true; }
379
						itemOut.first = true;
380
						itemOut.values = [{x: nowTime, y: 0}];
381
						myData[value].push(itemOut);
382

    
383
					});
384

    
385
					draw_graph(refreshInterval, then);
386

    
387
					$( "#traffic-graph-message" ).removeClass("text-danger").addClass("text-success");
388
					$( "#traffic-graph-message" ).text(message.success);
389

    
390
					setTimeout(function() {
391
						$( "#traffic-graph-message" ).empty();
392
						$( "#traffic-graph-message" ).removeClass("text-success");
393
					}, 5000);
394

    
395
				} else {
396

    
397
					$( "#traffic-graph-message" ).addClass("text-danger");
398
					$( "#traffic-graph-message" ).text(message.error);
399

    
400
					console.warn(message.error);
401

    
402
				}
403

    
404
	        })
405
	        .fail(function() {
406

    
407
			    console.warn( "The Traffic Graphs widget AJAX request failed." );
408

    
409
			});
410

    
411
	    } else {
412

    
413
			$( "#traffic-graph-message" ).addClass("text-danger");
414
			$( "#traffic-graph-message" ).text(error);
415

    
416
			console.warn(error);
417

    
418
	    }
419

    
420
        event.preventDefault();
421
    });
422

    
423
});
424
//]]>
425
</script>
426

    
427
<script src="/js/traffic-graphs.js"></script>
428

    
429
<script type="text/javascript">
430
//<![CDATA[
431

    
432
function updateBandwidth() {
433
	$.ajax(
434
		'/bandwidth_by_ip.php',
435
		{
436
			type: 'get',
437
			data: $(document.forms[0]).serialize(),
438
			success: function (data) {
439
				var hosts_split = data.split("|");
440

    
441
				$('#top10-hosts').empty();
442

    
443
				//parse top ten bandwidth abuser hosts
444
				for (var y=0; y<10; y++) {
445
					if ((y < hosts_split.length) && (hosts_split[y] != "") && (hosts_split[y] != "no info")) {
446
						hostinfo = hosts_split[y].split(";");
447

    
448
						$('#top10-hosts').append('<tr>'+
449
							'<td>'+ hostinfo[0] +'</td>'+
450
							'<td>'+ hostinfo[1] +' <?=gettext("Bits/sec");?></td>'+
451
							'<td>'+ hostinfo[2] +' <?=gettext("Bits/sec");?></td>'+
452
						'</tr>');
453
					}
454
				}
455
			},
456
	});
457
}
458

    
459
events.push(function() {
460
	$('form.auto-submit').on('change', function() {
461
		$(this).submit();
462
	});
463

    
464
	setInterval('updateBandwidth()', 3000);
465

    
466
	updateBandwidth();
467
});
468
//]]>
469
</script>
470
<?php
471

    
472
/* link the ipsec interface magically */
473
if (ipsec_enabled()) {
474
	$ifdescrs['enc0'] = gettext("IPsec");
475
}
476

    
477
?>
478
<div class="panel panel-default">
479
	<div class="panel-heading">
480
		<h2 class="panel-title"><?=gettext("Traffic Graph");?></h2>
481
	</div>
482
	<div class="panel-body">
483
		<div class="col-sm-6">
484
			<div id="traffic-chart-<?=$curif?>" class="d3-chart traffic-widget-chart">
485
				<svg></svg>
486
			</div>
487
		</div>
488
		<div class="col-sm-6">
489
			<table class="table table-striped table-condensed">
490
				<thead>
491
					<tr>
492
						<th><?=(($curhostipformat == "") ? gettext("Host IP") : gettext("Host Name or IP")); ?></th>
493
						<th><?=gettext("Bandwidth In"); ?></th>
494
						<th><?=gettext("Bandwidth Out"); ?></th>
495
					</tr>
496
				</thead>
497
				<tbody id="top10-hosts">
498
					<!-- to be added by javascript -->
499
				</tbody>
500
			</table>
501
		</div>
502
	</div>
503
</div>
504
<?php include("foot.inc");
(163-163/227)