Project

General

Profile

Download (14 KB) Statistics
| Branch: | Tag: | Revision:
1 ab6a5cfc Scott Ullrich
<?php
2
/*
3 325cdc5d sbeaver
	diag_packet_capture.php
4 ab6a5cfc Scott Ullrich
*/
5 fd9ebcd5 Stephen Beaver
/* ====================================================================
6
 *  Copyright (c)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved. 
7
 *
8
 *  Redistribution and use in source and binary forms, with or without modification, 
9
 *  are permitted provided that the following conditions are met: 
10
 *
11
 *  1. Redistributions of source code must retain the above copyright notice,
12
 *      this list of conditions and the following disclaimer.
13
 *
14
 *  2. Redistributions in binary form must reproduce the above copyright
15
 *      notice, this list of conditions and the following disclaimer in
16
 *      the documentation and/or other materials provided with the
17
 *      distribution. 
18
 *
19
 *  3. All advertising materials mentioning features or use of this software 
20
 *      must display the following acknowledgment:
21
 *      "This product includes software developed by the pfSense Project
22
 *       for use in the pfSense software distribution. (http://www.pfsense.org/). 
23
 *
24
 *  4. The names "pfSense" and "pfSense Project" must not be used to
25
 *       endorse or promote products derived from this software without
26
 *       prior written permission. For written permission, please contact
27
 *       coreteam@pfsense.org.
28
 *
29
 *  5. Products derived from this software may not be called "pfSense"
30
 *      nor may "pfSense" appear in their names without prior written
31
 *      permission of the Electric Sheep Fencing, LLC.
32
 *
33
 *  6. Redistributions of any form whatsoever must retain the following
34
 *      acknowledgment:
35
 *
36
 *  "This product includes software developed by the pfSense Project
37
 *  for use in the pfSense software distribution (http://www.pfsense.org/).
38
  *
39
 *  THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
40
 *  EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42
 *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
43
 *  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48
 *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50
 *  OF THE POSSIBILITY OF SUCH DAMAGE.
51
 *
52
 *  ====================================================================
53
 *
54
 */
55 ab6a5cfc Scott Ullrich
56 f35abee2 jim-p
/*
57 325cdc5d sbeaver
	pfSense_BUILDER_BINARIES:	/bin/ps /usr/bin/grep	/usr/sbin/tcpdump
58
	pfSense_MODULE: routing
59 13d193c2 Scott Ullrich
*/
60
61 6b07c15a Matthew Grooms
##|+PRIV
62
##|*IDENT=page-diagnostics-packetcapture
63
##|*NAME=Diagnostics: Packet Capture page
64
##|*DESCR=Allow access to the 'Diagnostics: Packet Capture' page.
65
##|*MATCH=diag_packet_capture.php*
66
##|-PRIV
67
68 7c9a30c8 jim-p
$allowautocomplete = true;
69
70 017e4ad3 jim-p
function fixup_host_logic($value) {
71
	return str_replace(array(" ", ",", "+", "|", "!"), array("", "and ", "and ", "or ", "not "), $value);
72
}
73 325cdc5d sbeaver
74 017e4ad3 jim-p
function strip_host_logic($value) {
75
	return str_replace(array(" ", ",", "+", "|", "!"), array("", "", "", "", ""), $value);
76
}
77 325cdc5d sbeaver
78 017e4ad3 jim-p
function get_host_boolean($value, $host) {
79
	$value = str_replace(array("!", $host), array("", ""), $value);
80
	$andor = "";
81
	switch (trim($value)) {
82
		case "|":
83
			$andor = "or ";
84
			break;
85
		case ",":
86
		case "+":
87
			$andor = "and ";
88
			break;
89
	}
90 325cdc5d sbeaver
91 017e4ad3 jim-p
	return $andor;
92
}
93 325cdc5d sbeaver
94 017e4ad3 jim-p
function has_not($value) {
95
	return strpos($value, '!') !== false;
96
}
97 325cdc5d sbeaver
98 715d2895 jim-p
function fixup_not($value) {
99
	return str_replace("!", "not ", $value);
100
}
101 325cdc5d sbeaver
102 715d2895 jim-p
function strip_not($value) {
103 017e4ad3 jim-p
	return ltrim(trim($value), '!');
104
}
105
106
function fixup_host($value, $position) {
107
	$host = strip_host_logic($value);
108
	$not = has_not($value) ? "not " : "";
109
	$andor = ($position > 0) ? get_host_boolean($value, $host) : "";
110 5f601060 Phil Davis
	if (is_ipaddr($host)) {
111 017e4ad3 jim-p
		return "{$andor}host {$not}" . $host;
112 5f601060 Phil Davis
	} elseif (is_subnet($host)) {
113 017e4ad3 jim-p
		return "{$andor}net {$not}" . $host;
114 5f601060 Phil Davis
	} else {
115 017e4ad3 jim-p
		return "";
116 5f601060 Phil Davis
	}
117 715d2895 jim-p
}
118
119 5f601060 Phil Davis
if ($_POST['downloadbtn'] == gettext("Download Capture")) {
120 f257c139 jim-p
	$nocsrf = true;
121 5f601060 Phil Davis
}
122 f257c139 jim-p
123 1c550bed Renato Botelho
$pgtitle = array(gettext("Diagnostics"), gettext("Packet Capture"));
124 d7cd7129 Scott Ullrich
require_once("guiconfig.inc");
125
require_once("pfsense-utils.inc");
126 ab6a5cfc Scott Ullrich
127 4e7d1665 Scott Ullrich
$fp = "/root/";
128 ab6a5cfc Scott Ullrich
$fn = "packetcapture.cap";
129 68ed7d9d Chris Buechler
$snaplen = 0;//default packet length
130 ab6a5cfc Scott Ullrich
$count = 100;//default number of packets to capture
131
132 fd8774c0 jim-p
$fams = array('ip', 'ip6');
133 715d2895 jim-p
$protos = array('icmp', 'icmp6', 'tcp', 'udp', 'arp', 'carp', 'esp',
134 325cdc5d sbeaver
		        '!icmp', '!icmp6', '!tcp', '!udp', '!arp', '!carp', '!esp');
135 fd8774c0 jim-p
136 391cd070 Darren Embry
$input_errors = array();
137
138 f7b6c87a Darren Embry
$interfaces = get_configured_interface_with_descr();
139 5f601060 Phil Davis
if (isset($config['ipsec']['enable'])) {
140 f7b6c87a Darren Embry
	$interfaces['ipsec'] = "IPsec";
141 5f601060 Phil Davis
}
142 f7b6c87a Darren Embry
foreach (array('server', 'client') as $mode) {
143
	if (is_array($config['openvpn']["openvpn-{$mode}"])) {
144
		foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
145
			if (!isset($setting['disable'])) {
146
				$interfaces['ovpn' . substr($mode, 0, 1) . $setting['vpnid']] = gettext("OpenVPN") . " ".$mode.": ".htmlspecialchars($setting['description']);
147
			}
148
		}
149
	}
150
}
151
152 ab6a5cfc Scott Ullrich
if ($_POST) {
153
	$host = $_POST['host'];
154
	$selectedif = $_POST['interface'];
155
	$count = $_POST['count'];
156 391cd070 Darren Embry
	$snaplen = $_POST['snaplen'];
157 ab6a5cfc Scott Ullrich
	$port = $_POST['port'];
158
	$detail = $_POST['detail'];
159 f35abee2 jim-p
	$fam = $_POST['fam'];
160 fd8774c0 jim-p
	$proto = $_POST['proto'];
161 f35abee2 jim-p
162 20e7e444 jim-p
	if (!array_key_exists($selectedif, $interfaces)) {
163 622caf8f Darren Embry
		$input_errors[] = gettext("Invalid interface.");
164
	}
165 325cdc5d sbeaver
166 622caf8f Darren Embry
	if ($fam !== "" && $fam !== "ip" && $fam !== "ip6") {
167
		$input_errors[] = gettext("Invalid address family.");
168
	}
169 325cdc5d sbeaver
170 715d2895 jim-p
	if ($proto !== "" && !in_array(strip_not($proto), $protos)) {
171 622caf8f Darren Embry
		$input_errors[] = gettext("Invalid protocol.");
172
	}
173 325cdc5d sbeaver
174 391cd070 Darren Embry
	if ($host != "") {
175 017e4ad3 jim-p
		$host_string = str_replace(array(" ", "|", ","), array("", "#|", "#+"), $host);
176 325cdc5d sbeaver
177 017e4ad3 jim-p
		if (strpos($host_string, '#') === false) {
178
			$hosts = array($host);
179
		} else {
180
			$hosts = explode('#', $host_string);
181
		}
182 325cdc5d sbeaver
183 017e4ad3 jim-p
		foreach ($hosts as $h) {
184
			if (!is_subnet(strip_host_logic($h)) && !is_ipaddr(strip_host_logic($h))) {
185
				$input_errors[] = sprintf(gettext("A valid IP address or CIDR block must be specified. [%s]"), $h);
186
			}
187 391cd070 Darren Embry
		}
188
	}
189 325cdc5d sbeaver
190 391cd070 Darren Embry
	if ($port != "") {
191 715d2895 jim-p
		if (!is_port(strip_not($port))) {
192 391cd070 Darren Embry
			$input_errors[] = gettext("Invalid value specified for port.");
193
		}
194
	}
195 325cdc5d sbeaver
196 391cd070 Darren Embry
	if ($snaplen == "") {
197
		$snaplen = 0;
198 b39ca83c Scott Ullrich
	} else {
199 391cd070 Darren Embry
		if (!is_numeric($snaplen) || $snaplen < 0) {
200
			$input_errors[] = gettext("Invalid value specified for packet length.");
201
		}
202
	}
203 325cdc5d sbeaver
204 391cd070 Darren Embry
	if ($count == "") {
205
		$count = 0;
206
	} else {
207
		if (!is_numeric($count) || $count < 0) {
208
			$input_errors[] = gettext("Invalid value specified for packet count.");
209
		}
210 ab6a5cfc Scott Ullrich
	}
211
212 391cd070 Darren Embry
	if (!count($input_errors)) {
213
		$do_tcpdump = true;
214 f35abee2 jim-p
215 391cd070 Darren Embry
		conf_mount_rw();
216 ab6a5cfc Scott Ullrich
217 8d64d6b5 N0YB
		if ($_POST['promiscuous']) {
218
			//if promiscuous mode is checked
219
			$disablepromiscuous = "";
220
		} else {
221
			//if promiscuous mode is unchecked
222
			$disablepromiscuous = "-p";
223
		}
224
225 391cd070 Darren Embry
		if ($_POST['dnsquery']) {
226
			//if dns lookup is checked
227
			$disabledns = "";
228
		} else {
229
			//if dns lookup is unchecked
230
			$disabledns = "-n";
231
		}
232 d5c2fde5 Scott Ullrich
233 699737d9 Phil Davis
		if ($_POST['startbtn'] != "") {
234 391cd070 Darren Embry
			$action = gettext("Start");
235 d5c2fde5 Scott Ullrich
236 391cd070 Darren Embry
			//delete previous packet capture if it exists
237 5f601060 Phil Davis
			if (file_exists($fp.$fn)) {
238 391cd070 Darren Embry
				unlink ($fp.$fn);
239 5f601060 Phil Davis
			}
240 391cd070 Darren Embry
241 699737d9 Phil Davis
		} elseif ($_POST['stopbtn'] != "") {
242 391cd070 Darren Embry
			$action = gettext("Stop");
243
			$processes_running = trim(shell_exec("/bin/ps axw -O pid= | /usr/bin/grep tcpdump | /usr/bin/grep {$fn} | /usr/bin/egrep -v '(pflog|grep)'"));
244
245
			//explode processes into an array, (delimiter is new line)
246
			$processes_running_array = explode("\n", $processes_running);
247
248
			//kill each of the packetcapture processes
249
			foreach ($processes_running_array as $process) {
250
				$process_id_pos = strpos($process, ' ');
251
				$process_id = substr($process, 0, $process_id_pos);
252
				exec("kill $process_id");
253
			}
254 d5c2fde5 Scott Ullrich
255 699737d9 Phil Davis
		} elseif ($_POST['downloadbtn'] != "") {
256 391cd070 Darren Embry
			//download file
257
			$fs = filesize($fp.$fn);
258
			header("Content-Type: application/octet-stream");
259
			header("Content-Disposition: attachment; filename=$fn");
260
			header("Content-Length: $fs");
261
			readfile($fp.$fn);
262
			exit;
263
		}
264 ab6a5cfc Scott Ullrich
	}
265 b39ca83c Scott Ullrich
} else {
266 ab6a5cfc Scott Ullrich
	$do_tcpdump = false;
267
}
268 f7b6c87a Darren Embry
269 325cdc5d sbeaver
$protocollist = array(
270
	'' => 'Any',
271
	'icmp' => 'ICMP',
272
	'!icmp' => 'Exclude ICMP',
273
	'icmp6' => 'ICMPv6',
274
	'!icmp6' => 'Exclude ICMPv6',
275
	'tcp' => 'TCP',
276
	'!tcp' => 'Exclude TCP',
277
	'udp' => 'UDP',
278
	'!udp' => 'Exclude UDP',
279
	'arp' => 'ARP',
280
	'!arp' => 'Exclude ARP',
281
	'carp' => 'CARP (VRRP)',
282
	'!carp' => 'Exclude CARP (VRRP)',
283
	'esp' => 'ESP'
284
);
285
286
include("head.inc");
287
288
if ($input_errors)
289
	print_input_errors($input_errors);
290
291
require('classes/Form.class.php');
292
293
$form = new Form(false); // No button yet. We add those later depending on the required action
294
295
$section = new Form_Section('General Logging Options');
296
297
$section->addInput(new Form_Select(
298
	'interface',
299
	'Interface',
300
	$selectedif,
301
	$interfaces
302
))->setHelp('Select the interface on which to capture traffic. ');
303
304
$section->addInput(new Form_Checkbox(
305
	'promiscuous',
306
	'Promiscuous',
307
	'Packet capture will be performed using promiscuous mode',
308
	$pconfig['promiscuous']
309
))->setHelp('Note: Some network adapters do not support or work well in promiscuous mode.'. '<br />' .
310
			'More: ' . '<a target="_blank" href="http://www.freebsd.org/cgi/man.cgi?query=tcpdump&amp;apropos=0&amp;sektion=0&amp;manpath=FreeBSD+8.3-stable&amp;arch=default&amp;format=html">' .
311
			'Packet capture' . '</a>');
312
313
$section->addInput(new Form_Select(
314
	'fam',
315
	'Address Family',
316
	$fam,
317
	array('' => 'Any',
318
		  'ip' => 'IPv4 Only',
319
		  'ip6' => 'IPv6 Only'
320
	)
321
))->setHelp('Select the type of traffic to be captured');
322
323
$section->addInput(new Form_Select(
324
	'proto',
325
	'Protocol',
326
	$proto,
327
	$protocollist
328
))->setHelp('Select the protocol to capture, or "Any". ');
329
330
$section->addInput(new Form_Input(
331
	'host',
332
	'Host Address',
333
	'text',
334
	$host
335
))->setHelp('This value is either the Source or Destination IP address or subnet in CIDR notation. The packet capture will look for this address in either field.' . '<br />' .
336
			'Matching can be negated by preceding the value with "!". Multiple IP addresses or CIDR subnets may be specified. Comma (",") separated values perform a boolean "AND". ' .
337
			'Separating with a pipe ("|") performs a boolean "OR".' . '<br />' .
338
			'If you leave this field blank, all packets on the specified interface will be captured.');
339
340
$section->addInput(new Form_Input(
341
	'port',
342
	'Port',
343
	'text',
344
	$port
345
))->setHelp('The port can be either the source or destination port. The packet capture will look for this port in either field. ' .
346
			'Leave blank if you do not want to filter by port.');
347
348
$section->addInput(new Form_Input(
349
	'snaplen',
350
	'Packet Length',
351
	'text',
352
	$snaplen
353
))->setHelp('The Packet length is the number of bytes of each packet that will be captured. Default value is 0, ' .
354
			'which will capture the entire frame regardless of its size.');
355
356
$section->addInput(new Form_Input(
357
	'count',
358
	'Count',
359
	'text',
360
	$count
361
))->setHelp('This is the number of packets the packet capture will grab. Default value is 100.' . '<br />' .
362
			'Enter 0 (zero) for no count limit.');
363
364
$section->addInput(new Form_Select(
365
	'detail',
366
	'Level of detail',
367
	$detail,
368
	array('' => 'Any',
369
		  'normal' => 'Normal',
370
		  'medium' => 'Medium',
371
		  'high' => 'High',
372
		  'full' => 'Full',
373
	)
374
))->setHelp('This is the level of detail that will be displayed after hitting "Stop" when the packets have been captured.' . '<br />' .
375
			'This option does not affect the level of detail when downloading the packet capture. ');
376
377
$section->addInput(new Form_Checkbox(
378
	'dnsquery',
379
	'Reverse DNS Lookup',
380
	null,
381
	$_POST['dnsquery']
382
))->setHelp('This check box will cause the packet capture to perform a reverse DNS lookup associated with all IP addresses.' . '<br />' .
383
			'This option can cause delays for large packet captures.');
384
385
$form->add($section);
386
387
/* check to see if packet capture tcpdump is already running */
388
$processcheck = (trim(shell_exec("/bin/ps axw -O pid= | /usr/bin/grep tcpdump | /usr/bin/grep {$fn} | /usr/bin/egrep -v '(pflog|grep)'")));
389
390
$processisrunning = ($processcheck != "");
391
392
if (($action == gettext("Stop") or $action == "") and $processisrunning != true) {
393
	$form->addGlobal(new Form_Button(
394
		'startbtn',
395
		'Start'
396
	))->removeClass('btn-primary')->addClass('btn-success');
397
}
398
else {
399
	$form->addGlobal(new Form_Button(
400
		'stopbtn',
401
		'Stop'
402
	))->removeClass('btn-primary')->addClass('btn-warning');
403
}
404 b39ca83c Scott Ullrich
405 325cdc5d sbeaver
if (file_exists($fp.$fn) and $processisrunning != true) {
406
	$form->addGlobal(new Form_Button(
407
		'viewbtn',
408
		'View Capture'
409
	))->removeClass('btn-primary');
410
411
	$form->addGlobal(new Form_Button(
412
		'downloadbtn',
413
		'Download Capture'
414
	))->removeClass('btn-primary');
415
416
	$section->addInput(new Form_StaticText(
417
		'Last capture',
418
		date("F jS, Y g:i:s a.", filemtime($fp.$fn))
419
	));
420
}
421 b39ca83c Scott Ullrich
422 325cdc5d sbeaver
print($form);
423 ab6a5cfc Scott Ullrich
424 325cdc5d sbeaver
if ($do_tcpdump) :
425
	$matches = array();
426 d5c2fde5 Scott Ullrich
427 325cdc5d sbeaver
	if (in_array($fam, $fams))
428
		$matches[] = $fam;
429 89fae3e7 jim-p
430 325cdc5d sbeaver
	if (in_array($proto, $protos))
431
		$matches[] = fixup_not($proto);
432 89fae3e7 jim-p
433 325cdc5d sbeaver
	if ($port != "")
434
		$matches[] = "port ".fixup_not($port);
435 89fae3e7 jim-p
436 325cdc5d sbeaver
	if ($host != "") {
437
		$hostmatch = "";
438
		$hostcount = 0;
439 89fae3e7 jim-p
440 325cdc5d sbeaver
		foreach ($hosts as $h) {
441
			$h = fixup_host($h, $hostcount++);
442 89fae3e7 jim-p
443 325cdc5d sbeaver
			if (!empty($h))
444
				$hostmatch .= " " . $h;
445
		}
446 fd8774c0 jim-p
447 325cdc5d sbeaver
		if (!empty($hostmatch))
448
			$matches[] = "({$hostmatch})";
449
	}
450 89fae3e7 jim-p
451 325cdc5d sbeaver
	if ($count != "0" ) {
452
		$searchcount = "-c " . $count;
453
	} else {
454
		$searchcount = "";
455
	}
456 89fae3e7 jim-p
457 325cdc5d sbeaver
	$selectedif = convert_friendly_interface_to_real_interface_name($selectedif);
458
459
	if ($action == gettext("Start")) {
460
		$matchstr = implode($matches, " and ");
461
462
		print_info_box(gettext('Packet Capture is running'), 'info');
463
464
		$cmd = "/usr/sbin/tcpdump -i {$selectedif} {$disablepromiscuous} {$searchcount} -s {$snaplen} -w {$fp}{$fn} " . escapeshellarg($matchstr);
465
		// Debug
466
		//echo $cmd;
467
		mwexec_bg ($cmd);
468
	} else {
469 b39ca83c Scott Ullrich
?>
470 325cdc5d sbeaver
471
<div class="panel panel-default">
472 f17594c7 Sjon Hortensius
	<div class="panel-heading"><h2 class="panel-title"><?=gettext('Packets Captured')?></h2></div>
473 325cdc5d sbeaver
	<div class="panel-body">
474
475 b39ca83c Scott Ullrich
<?php
476 325cdc5d sbeaver
		$detail_args = "";
477
		switch ($detail) {
478
			case "full":
479
				$detail_args = "-vv -e";
480
				break;
481
			case "high":
482
				$detail_args = "-vv";
483
				break;
484
			case "medium":
485
				$detail_args = "-v";
486
				break;
487
			case "normal":
488
			default:
489
				$detail_args = "-q";
490
				break;
491 89fae3e7 jim-p
		}
492 4e7d1665 Scott Ullrich
493 325cdc5d sbeaver
		print('<pre>');
494
		system("/usr/sbin/tcpdump {$disabledns} {$detail_args} -r {$fp}{$fn}");
495
		print('</pre>');
496
497
		conf_mount_ro();
498 4e7d1665 Scott Ullrich
?>
499 325cdc5d sbeaver
	</div>
500
</div>
501
<?php
502
	}
503
endif;
504
505
include("foot.inc");