Projet

Général

Profil

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

univnautes / etc / inc / filter_log.inc @ c4107752

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 $field) {
99
		if ($fields[$field] == "All") continue;
100
		if ((strpos($fields[$field], '!') === 0)) {
101
			$fields[$field] = substr($fields[$field], 1);
102
			if (preg_match("/act/i", $field)) {
103
				if ( (in_arrayi($flent[$field], explode(",", str_replace(" ", ",", $fields[$field]))) ) ) return false;
104
			} else {
105
				$field_regex = escape_filter_regex($fields[$field]);
106
				if ( (@preg_match("/{$field_regex}/i", $flent[$field])) )
107
					return false;
108
			}
109
		}
110
		else {
111
			if (preg_match("/act/i", $field)) {
112
				if ( !(in_arrayi($flent[$field], explode(",", str_replace(" ", ",", $fields[$field]))) ) ) return false;
113
			} else {
114
				$field_regex = escape_filter_regex($fields[$field]);
115
				if ( !(@preg_match("/{$field_regex}/i", $flent[$field])) )
116
					return false;
117
			}
118
		}
119
	}	
120
	return true;
121
}
122

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

    
128
function parse_filter_line($line) {
129
	global $config, $g;
130

    
131
	$flent = array();
132
	$log_split = "";
133

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

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

    
139
	$rule_data = explode(",", $rule);
140
	$field = 0;
141

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

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

    
171
		$flent['length'] = $rule_data[$field++];
172
		$flent['srcip'] = $rule_data[$field++];
173
		$flent['dstip'] = $rule_data[$field++];
174

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

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

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

    
195
			$flent['icmp_type'] = $rule_data[$field++];
196

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

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

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

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

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

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

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

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

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

    
304
	return "";
305
}
306

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

    
315
	$_gb = exec("/sbin/pfctl -vvPsn -a \"miniupnpd\" | grep '^@'", $buffer);
316
	if (is_array($buffer)) {
317
		foreach ($buffer as $line) {
318
			list($key, $value) = explode (" ", $line, 2);
319
			$buffer_rules_rdr[$key] = $value;
320
		}
321
	}
322
	unset($buffer, $_gb);
323
	if (file_exists("{$g['tmp_path']}/rules.debug"))
324
		$_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);
325
	else
326
		$_gb = exec("/sbin/pfctl -vvPsr | /usr/bin/egrep '^@[0-9]+\([0-9]+\)[[:space:]].*[[:space:]]log[[:space:]]'", $buffer);
327

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

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

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

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

    
358
	if ($type == "rdr")	{
359
		$ruleString = $buffer_rules_rdr[$lookup_key];
360
		//TODO: get the correct 'description' part of a RDR log line. currently just first 30 characters..
361
		$rulename = substr($ruleString,0,30);
362
	} else {
363
		$ruleString = $buffer_rules_normal[$lookup_key];
364
		list(,$rulename,) = explode("\"",$ruleString);
365
		$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);
366
	}
367
	return "{$rulename} ({$lookup_key})";
368
}
369

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

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

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

    
413
?>
(20-20/68)