Projet

Général

Profil

Télécharger (14,4 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / filter_log.inc @ 0b857543

1
<?php
2
/* $Id$ */
3
/*
4
	filter_log.inc
5
	part of pfSesne by Scott Ullrich
6
	originally based on m0n0wall (http://m0n0.ch/wall)
7

    
8
	Copyright (C) 2009 Jim Pingle <myfirstname>@<mylastname>.org
9
	All rights reserved.
10

    
11
	Redistribution and use in source and binary forms, with or without
12
	modification, are permitted provided that the following conditions are met:
13

    
14
	1. Redistributions of source code must retain the above copyright notice,
15
	   this list of conditions and the following disclaimer.
16

    
17
	2. Redistributions in binary form must reproduce the above copyright
18
	   notice, this list of conditions and the following disclaimer in the
19
	   documentation and/or other materials provided with the distribution.
20

    
21
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
23
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
	POSSIBILITY OF SUCH DAMAGE.
31
*/
32
/*
33
	pfSense_BUILDER_BINARIES:	/usr/sbin/fifolog_reader	/usr/bin/tail	/usr/local/sbin/clog
34
	pfSense_MODULE:	filter
35
*/
36

    
37
require 'config.inc';
38

    
39
global $buffer_rules_rdr, $buffer_rules_normal;
40
$buffer_rules_rdr = array();
41
$buffer_rules_normal = array();
42

    
43
/* format filter logs */
44
function conv_log_filter($logfile, $nentries, $tail = 50, $filtertext = "", $filterinterface = null) {
45
	global $config, $g;
46

    
47
	/* Make sure this is a number before using it in a system call */
48
	if (!(is_numeric($tail)))
49
		return;
50

    
51
	if ($filtertext)
52
		$tail = 5000;
53

    
54
	/* Always do a reverse tail, to be sure we're grabbing the 'end' of the log. */
55
	$logarr = "";
56

    
57
	if(isset($config['system']['usefifolog']))
58
		exec("/usr/sbin/fifolog_reader " . escapeshellarg($logfile) . " | /usr/bin/grep 'filterlog:' | /usr/bin/tail -r -n {$tail}", $logarr);
59
	else
60
		exec("/usr/local/sbin/clog " . escapeshellarg($logfile) . " | grep -v \"CLOG\" | grep -v \"\033\" | /usr/bin/grep 'filterlog:' | /usr/bin/tail -r -n {$tail}", $logarr);
61

    
62
	$filterlog = array();
63
	$counter = 0;
64

    
65
	$filterinterface = strtoupper($filterinterface);
66
	foreach ($logarr as $logent) {
67
		if($counter >= $nentries)
68
			break;
69

    
70
		$flent = parse_filter_line($logent);
71
		if (!$filterinterface || ($filterinterface == $flent['interface']))
72
		{
73
			if ( ( ($flent != "") && (!is_array($filtertext)) && (match_filter_line ($flent, $filtertext))) || 
74
			     ( ($flent != "") && ( is_array($filtertext)) && (match_filter_field($flent, $filtertext)) ) ) {
75
				$counter++;
76
				$filterlog[] = $flent;
77
			}
78
		}
79
	}
80
	/* Since the lines are in reverse order, flip them around if needed based on the user's preference */
81
	return isset($config['syslog']['reverse']) ? $filterlog : array_reverse($filterlog);
82
}
83

    
84
function escape_filter_regex($filtertext) {
85
	/* If the caller (user) has not already put a backslash before a slash, to escape it in the regex, */
86
	/* then this will do it. Take out any "\/" already there, then turn all ordinary "/" into "\/".  */
87
	return str_replace('/', '\/', str_replace('\/', '/', $filtertext));
88
}
89

    
90
function match_filter_line($flent, $filtertext = "") {
91
	if (!$filtertext)
92
		return true;
93
	$filtertext = escape_filter_regex(str_replace(' ', '\s+', $filtertext));
94
	return @preg_match("/{$filtertext}/i", implode(" ", array_values($flent)));
95
}
96

    
97
function match_filter_field($flent, $fields) {
98
	foreach ($fields as $key => $field) {
99
		if ($field == "All")
100
			continue;
101
		if ((strpos($field, '!') === 0)) {
102
			$field = substr($field, 1);
103
			if (strtolower($key) == 'act') {
104
				if (in_arrayi($flent[$key], explode(" ", $field)))
105
					return false;
106
			} else {
107
				$field_regex = escape_filter_regex($field);
108
				if (@preg_match("/{$field_regex}/i", $flent[$key]))
109
					return false;
110
			}
111
		} else {
112
			if (strtolower($key) == 'act') {
113
				if (!in_arrayi($flent[$key], explode(" ", $field)))
114
					return false;
115
			} else {
116
				$field_regex = escape_filter_regex($field);
117
				if (!@preg_match("/{$field_regex}/i", $flent[$key]))
118
					return false;
119
			}
120
		}
121
	}
122
	return true;
123
}
124

    
125
// Case Insensitive in_array function
126
function in_arrayi($needle, $haystack) {
127
	return in_array(strtolower($needle), array_map('strtolower', $haystack));
128
}
129

    
130
function parse_filter_line($line) {
131
	global $config, $g;
132

    
133
	$flent = array();
134
	$log_split = "";
135

    
136
	if (!preg_match("/(.*)\s(.*)\sfilterlog:\s(.*)$/", $line, $log_split))
137
		return "";
138

    
139
	list($all, $flent['time'], $host, $rule) = $log_split;
140

    
141
	$rule_data = explode(",", $rule);
142
	$field = 0;
143

    
144
	$flent['rulenum'] = $rule_data[$field++];
145
	$flent['subrulenum'] = $rule_data[$field++];
146
	$flent['anchor'] = $rule_data[$field++];
147
	$flent['tracker'] = $rule_data[$field++];
148
	$flent['realint'] = $rule_data[$field++];
149
	$flent['interface']  = convert_real_interface_to_friendly_descr($flent['realint']);
150
	$flent['reason'] = $rule_data[$field++];
151
	$flent['act'] = $rule_data[$field++];
152
	$flent['direction'] = $rule_data[$field++];
153
	$flent['version'] = $rule_data[$field++];
154

    
155
	if ($flent['version'] == '4' || $flent['version'] == '6') {
156
		if ($flent['version'] == '4') {
157
			$flent['tos'] = $rule_data[$field++];
158
			$flent['ecn'] = $rule_data[$field++];
159
			$flent['ttl'] = $rule_data[$field++];
160
			$flent['id'] = $rule_data[$field++];
161
			$flent['offset'] = $rule_data[$field++];
162
			$flent['flags'] = $rule_data[$field++];
163
			$flent['protoid'] = $rule_data[$field++];
164
			$flent['proto'] = strtoupper($rule_data[$field++]);
165
		} else {
166
			$flent['class'] = $rule_data[$field++];
167
			$flent['flowlabel'] = $rule_data[$field++];
168
			$flent['hlim'] = $rule_data[$field++];
169
			$flent['proto'] = $rule_data[$field++];
170
			$flent['protoid'] = $rule_data[$field++];
171
		}
172

    
173
		$flent['length'] = $rule_data[$field++];
174
		$flent['srcip'] = $rule_data[$field++];
175
		$flent['dstip'] = $rule_data[$field++];
176

    
177
		if ($flent['protoid'] == '6' || $flent['protoid'] == '17') { // TCP or UDP
178
			$flent['srcport'] = $rule_data[$field++];
179
			$flent['dstport'] = $rule_data[$field++];
180

    
181
			$flent['src'] = $flent['srcip'] . ':' . $flent['srcport'];
182
			$flent['dst'] = $flent['dstip'] . ':' . $flent['dstport'];
183

    
184
			$flent['datalen'] = $rule_data[$field++];
185
			if ($flent['protoid'] == '6') { // TCP
186
				$flent['tcpflags'] = $rule_data[$field++];
187
				$flent['seq'] = $rule_data[$field++];
188
				$flent['ack'] = $rule_data[$field++];
189
				$flent['window'] = $rule_data[$field++];
190
				$flent['urg'] = $rule_data[$field++];
191
				$flent['options'] = explode(";",$rule_data[$field++]);
192
			}
193
		} else if ($flent['protoid'] == '1') { // ICMP
194
			$flent['src'] = $flent['srcip'];
195
			$flent['dst'] = $flent['dstip'];
196

    
197
			$flent['icmp_type'] = $rule_data[$field++];
198

    
199
			switch ($flent['icmp_type']) {
200
			case "request":
201
			case "reply":
202
				$flent['icmp_id'] = $rule_data[$field++];
203
				$flent['icmp_seq'] = $rule_data[$field++];
204
				break;
205
			case "unreachproto":
206
				$flent['icmp_dstip'] = $rule_data[$field++];
207
				$flent['icmp_protoid'] = $rule_data[$field++];
208
				break;
209
			case "unreachport":
210
				$flent['icmp_dstip'] = $rule_data[$field++];
211
				$flent['icmp_protoid'] = $rule_data[$field++];
212
				$flent['icmp_port'] = $rule_data[$field++];
213
				break;
214
			case "unreach":
215
			case "timexceed":
216
			case "paramprob":
217
			case "redirect":
218
			case "maskreply":
219
				$flent['icmp_descr'] = $rule_data[$field++];
220
				break;
221
			case "needfrag":
222
				$flent['icmp_dstip'] = $rule_data[$field++];
223
				$flent['icmp_mtu'] = $rule_data[$field++];
224
				break;
225
			case "tstamp":
226
				$flent['icmp_id'] = $rule_data[$field++];
227
				$flent['icmp_seq'] = $rule_data[$field++];
228
				break;
229
			case "tstampreply":
230
				$flent['icmp_id'] = $rule_data[$field++];
231
				$flent['icmp_seq'] = $rule_data[$field++];
232
				$flent['icmp_otime'] = $rule_data[$field++];
233
				$flent['icmp_rtime'] = $rule_data[$field++];
234
				$flent['icmp_ttime'] = $rule_data[$field++];
235
				break;
236
			default :
237
				$flent['icmp_descr'] = $rule_data[$field++];
238
				break;
239
			}
240

    
241
		} else if ($flent['protoid'] == '112') { // CARP
242
			$flent['type'] = $rule_data[$field++];
243
			$flent['ttl'] = $rule_data[$field++];
244
			$flent['vhid'] = $rule_data[$field++];
245
			$flent['version'] = $rule_data[$field++];
246
			$flent['advskew'] = $rule_data[$field++];
247
			$flent['advbase'] = $rule_data[$field++];
248
		}
249
	} else {
250
		if($g['debug'])
251
			log_error(sprintf(gettext("There was a error parsing rule number: %s.   Please report to mailing list or forum."), $flent['rulenum']));
252
		return "";
253
	}
254

    
255
	/* If there is a src, a dst, and a time, then the line should be usable/good */
256
	if (!((trim($flent['src']) == "") || (trim($flent['dst']) == "") || (trim($flent['time']) == ""))) {
257
		return $flent;
258
	} else {
259
		if($g['debug']) {
260
			log_error(sprintf(gettext("There was a error parsing rule: %s.   Please report to mailing list or forum."), $errline));
261
		}
262
		return "";
263
	}
264
}
265

    
266
function get_port_with_service($port, $proto) {
267
	if (!$port)
268
		return '';
269

    
270
	$service = getservbyport($port, $proto);
271
	$portstr = "";
272
	if ($service) {
273
		$portstr = sprintf('<span title="' . gettext('Service %1$s/%2$s: %3$s') . '">' . htmlspecialchars($port) . '</span>', $port, $proto, $service);
274
	} else {
275
		$portstr = htmlspecialchars($port);
276
	}
277
	return ':' . $portstr;
278
}
279

    
280
function find_rule_by_number($rulenum, $trackernum, $type="block") {
281
	global $g;
282

    
283
	/* Passing arbitrary input to grep could be a Very Bad Thing(tm) */
284
	if (!is_numeric($rulenum) || !is_numeric($trackernum) || !in_array($type, array('pass', 'block', 'match', 'rdr')))
285
		return;
286

    
287
	if ($trackernum == "0")
288
		$lookup_pattern = "^@{$rulenum}\([0-9]+\)[[:space:]]{$type}[[:space:]].*[[:space:]]log[[:space:]]";
289
	else
290
		$lookup_pattern = "^@[0-9]+\({$trackernum}\)[[:space:]]{$type}[[:space:]].*[[:space:]]log[[:space:]]";
291

    
292
	/* At the moment, miniupnpd is the only thing I know of that
293
	   generates logging rdr rules */
294
	unset($buffer);
295
	if ($type == "rdr")
296
		$_gb = exec("/sbin/pfctl -vvPsn -a \"miniupnpd\" | /usr/bin/egrep " . escapeshellarg("^@{$rulenum}"), $buffer);
297
	else {
298
		if (file_exists("{$g['tmp_path']}/rules.debug"))
299
			$_gb = exec("/sbin/pfctl -vvPnf {$g['tmp_path']}/rules.debug 2>/dev/null | /usr/bin/egrep " . escapeshellarg($lookup_pattern), $buffer);
300
		else
301
			$_gb = exec("/sbin/pfctl -vvPsr | /usr/bin/egrep " . escapeshellarg($lookup_pattern), $buffer);
302
	}
303
	if (is_array($buffer))
304
		return $buffer[0];
305

    
306
	return "";
307
}
308

    
309
function buffer_rules_load() {
310
	global $g, $buffer_rules_rdr, $buffer_rules_normal;
311
	unset($buffer, $buffer_rules_rdr, $buffer_rules_normal);
312
	/* Redeclare globals after unset to work around PHP */
313
	global $buffer_rules_rdr, $buffer_rules_normal;
314
	$buffer_rules_rdr = array();
315
	$buffer_rules_normal = array();
316

    
317
	$_gb = exec("/sbin/pfctl -vvPsn -a \"miniupnpd\" | grep '^@'", $buffer);
318
	if (is_array($buffer)) {
319
		foreach ($buffer as $line) {
320
			list($key, $value) = explode (" ", $line, 2);
321
			$buffer_rules_rdr[$key] = $value;
322
		}
323
	}
324
	unset($buffer, $_gb);
325
	if (file_exists("{$g['tmp_path']}/rules.debug"))
326
		$_gb = exec("/sbin/pfctl -vvPnf {$g['tmp_path']}/rules.debug 2>/dev/null | /usr/bin/egrep '^@[0-9]+\([0-9]+\)[[:space:]].*[[:space:]]log[[:space:]]' | /usr/bin/egrep -v '^@[0-9]+\([0-9]+\)[[:space:]](nat|rdr|binat|no|scrub)'", $buffer);
327
	else
328
		$_gb = exec("/sbin/pfctl -vvPsr | /usr/bin/egrep '^@[0-9]+\([0-9]+\)[[:space:]].*[[:space:]]log[[:space:]]'", $buffer);
329

    
330
	if (is_array($buffer)) {
331
		foreach ($buffer as $line) {
332
			list($key, $value) = explode (" ", $line, 2);
333
			# pfctl rule number output with tracker number: @dd(dddddddddd)
334
			$matches = array();
335
			if (preg_match('/\@(?P<rulenum>\d+)\((?<trackernum>\d+)\)/', $key, $matches) == 1) {
336
				if ($matches['trackernum'] > 0)
337
					$key = $matches['trackernum'];
338
				else
339
					$key = "@{$matches['rulenum']}";
340
			}
341
			$buffer_rules_normal[$key] = $value;
342
		}
343
	}
344
	unset($_gb, $buffer);
345
}
346

    
347
function buffer_rules_clear() {
348
	unset($GLOBALS['buffer_rules_normal']);
349
	unset($GLOBALS['buffer_rules_rdr']);
350
}
351

    
352
function find_rule_by_number_buffer($rulenum, $trackernum, $type){
353
	global $g, $buffer_rules_rdr, $buffer_rules_normal;
354

    
355
	if ($trackernum == "0")
356
		$lookup_key = "@{$rulenum}";
357
	else
358
		$lookup_key = $trackernum;
359

    
360
	if ($type == "rdr")	{
361
		$ruleString = $buffer_rules_rdr[$lookup_key];
362
		//TODO: get the correct 'description' part of a RDR log line. currently just first 30 characters..
363
		$rulename = substr($ruleString,0,30);
364
	} else {
365
		$ruleString = $buffer_rules_normal[$lookup_key];
366
		list(,$rulename,) = explode("\"",$ruleString);
367
		$rulename = str_replace("USER_RULE: ",'<img src="/themes/'.$g['theme'].'/images/icons/icon_frmfld_user.png" width="11" height="12" title="USER_RULE" alt="USER_RULE"/> ',$rulename);
368
	}
369
	return "{$rulename} ({$lookup_key})";
370
}
371

    
372
function find_action_image($action) {
373
	global $g;
374
	if ((strstr(strtolower($action), "p")) || (strtolower($action) == "rdr"))
375
		return "/themes/{$g['theme']}/images/icons/icon_pass.gif";
376
	else if(strstr(strtolower($action), "r"))
377
		return "/themes/{$g['theme']}/images/icons/icon_reject.gif";
378
	else
379
		return "/themes/{$g['theme']}/images/icons/icon_block.gif";
380
}
381

    
382
/* AJAX specific handlers */
383
function handle_ajax($nentries, $tail = 50) {
384
	global $config;
385
	if($_GET['lastsawtime'] or $_POST['lastsawtime']) {
386
		global $filter_logfile,$filterent;
387
		if($_GET['lastsawtime'])
388
			$lastsawtime = $_GET['lastsawtime'];
389
		if($_POST['lastsawtime'])
390
			$lastsawtime = $_POST['lastsawtime'];
391
		/*  compare lastsawrule's time stamp to filter logs.
392
		 *  afterwards return the newer records so that client
393
		 *  can update AJAX interface screen.
394
		 */
395
		$new_rules = "";
396
		$filterlog = conv_log_filter($filter_logfile, $nentries, $tail);
397
		/* We need this to always be in forward order for the AJAX update to work properly */
398
		$filterlog = isset($config['syslog']['reverse']) ? array_reverse($filterlog) : $filterlog;
399
		foreach($filterlog as $log_row) {
400
			$row_time = strtotime($log_row['time']);
401
			$img = "<img border='0' src='" . find_action_image($log_row['act']) . "' alt={$log_row['act']} title={$log_row['act']} />";
402
			if($row_time > $lastsawtime) {
403
				if ($log_row['proto'] == "TCP")
404
					$log_row['proto'] .= ":{$log_row['tcpflags']}";
405

    
406
				$img = "<a href=\"#\" onClick=\"javascript:getURL('diag_logs_filter.php?getrulenum={$log_row['rulenum']},{$log_row['rulenum']}', outputrule);\">{$img}</a>";
407
				$new_rules .= "{$img}||{$log_row['time']}||{$log_row['interface']}||{$log_row['srcip']}||{$log_row['dst']}||{$log_row['proto']}||" . time() . "||\n";
408
			}
409
		}
410
		echo $new_rules;
411
		exit;
412
	}
413
}
414

    
415
?>
(20-20/68)