Projet

Général

Profil

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

univnautes / etc / inc / filter_log.inc @ efa26483

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 match_filter_line($flent, $filtertext = "") {
85
	if (!$filtertext)
86
		return true;
87
	$filtertext = str_replace(' ', '\s+', $filtertext);
88
	return preg_match("/{$filtertext}/i", implode(" ", array_values($flent)));
89
}
90

    
91
function match_filter_field($flent, $fields) {
92
	foreach ($fields as $field) {
93
		if ($fields[$field] == "All") continue;
94
		if ((strpos($fields[$field], '!') === 0)) {
95
			$fields[$field] = substr($fields[$field], 1);
96
			if (preg_match("/act/i", $field)) {
97
				if ( (in_arrayi($flent[$field], explode(",", str_replace(" ", ",", $fields[$field]))) ) ) return false;
98
			} else if ( (preg_match("/{$fields[$field]}/i", $flent[$field])) ) return false;
99
		}
100
		else {
101
			if (preg_match("/act/i", $field)) {
102
				if ( !(in_arrayi($flent[$field], explode(",", str_replace(" ", ",", $fields[$field]))) ) ) return false;
103
			} else if ( !(preg_match("/{$fields[$field]}/i", $flent[$field])) ) return false;
104
		}
105
	}	
106
	return true;
107
}
108

    
109
// Case Insensitive in_array function
110
function in_arrayi($needle, $haystack) {
111
	return in_array(strtolower($needle), array_map('strtolower', $haystack));
112
}
113

    
114
function parse_filter_line($line) {
115
	global $config, $g;
116

    
117
	$flent = array();
118
	$log_split = "";
119

    
120
	if (!preg_match("/(.*)\s(.*)\sfilterlog:\s(.*)$/", $line, $log_split))
121
		return "";
122

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

    
125
	$rule_data = explode(",", $rule);
126
	$field = 0;
127

    
128
	$flent['rulenum'] = $rule_data[$field++];
129
	$flent['subrulenum'] = $rule_data[$field++];
130
	$flent['anchor'] = $rule_data[$field++];
131
	$flent['tracker'] = $rule_data[$field++];
132
	$flent['realint'] = $rule_data[$field++];
133
	$flent['interface']  = convert_real_interface_to_friendly_descr($flent['realint']);
134
	$flent['reason'] = $rule_data[$field++];
135
	$flent['act'] = $rule_data[$field++];
136
	$flent['direction'] = $rule_data[$field++];
137
	$flent['version'] = $rule_data[$field++];
138

    
139
	if ($flent['version'] == '4' || $flent['version'] == '6') {
140
		if ($flent['version'] == '4') {
141
			$flent['tos'] = $rule_data[$field++];
142
			$flent['ecn'] = $rule_data[$field++];
143
			$flent['ttl'] = $rule_data[$field++];
144
			$flent['id'] = $rule_data[$field++];
145
			$flent['offset'] = $rule_data[$field++];
146
			$flent['flags'] = $rule_data[$field++];
147
			$flent['protoid'] = $rule_data[$field++];
148
			$flent['proto'] = strtoupper($rule_data[$field++]);
149
		} else {
150
			$flent['class'] = $rule_data[$field++];
151
			$flent['flowlabel'] = $rule_data[$field++];
152
			$flent['hlim'] = $rule_data[$field++];
153
			$flent['proto'] = $rule_data[$field++];
154
			$flent['protoid'] = $rule_data[$field++];
155
		}
156

    
157
		$flent['length'] = $rule_data[$field++];
158
		$flent['srcip'] = $rule_data[$field++];
159
		$flent['dstip'] = $rule_data[$field++];
160

    
161
		if ($flent['protoid'] == '6' || $flent['protoid'] == '17') { // TCP or UDP
162
			$flent['srcport'] = $rule_data[$field++];
163
			$flent['dstport'] = $rule_data[$field++];
164

    
165
			$flent['src'] = $flent['srcip'] . ':' . $flent['srcport'];
166
			$flent['dst'] = $flent['dstip'] . ':' . $flent['dstport'];
167

    
168
			$flent['datalen'] = $rule_data[$field++];
169
			if ($flent['protoid'] == '6') { // TCP
170
				$flent['tcpflags'] = $rule_data[$field++];
171
				$flent['seq'] = $rule_data[$field++];
172
				$flent['ack'] = $rule_data[$field++];
173
				$flent['window'] = $rule_data[$field++];
174
				$flent['urg'] = $rule_data[$field++];
175
				$flent['options'] = explode(";",$rule_data[$field++]);
176
			}
177
		} else if ($flent['protoid'] == '1') { // ICMP
178
			$flent['src'] = $flent['srcip'];
179
			$flent['dst'] = $flent['dstip'];
180

    
181
			$flent['icmp_type'] = $rule_data[$field++];
182

    
183
			switch ($flent['icmp_type']) {
184
			case "request":
185
			case "reply":
186
				$flent['icmp_id'] = $rule_data[$field++];
187
				$flent['icmp_seq'] = $rule_data[$field++];
188
				break;
189
			case "unreachproto":
190
				$flent['icmp_dstip'] = $rule_data[$field++];
191
				$flent['icmp_protoid'] = $rule_data[$field++];
192
				break;
193
			case "unreachport":
194
				$flent['icmp_dstip'] = $rule_data[$field++];
195
				$flent['icmp_protoid'] = $rule_data[$field++];
196
				$flent['icmp_port'] = $rule_data[$field++];
197
				break;
198
			case "unreach":
199
			case "timexceed":
200
			case "paramprob":
201
			case "redirect":
202
			case "maskreply":
203
				$flent['icmp_descr'] = $rule_data[$field++];
204
				break;
205
			case "needfrag":
206
				$flent['icmp_dstip'] = $rule_data[$field++];
207
				$flent['icmp_mtu'] = $rule_data[$field++];
208
				break;
209
			case "tstamp":
210
				$flent['icmp_id'] = $rule_data[$field++];
211
				$flent['icmp_seq'] = $rule_data[$field++];
212
				break;
213
			case "tstampreply":
214
				$flent['icmp_id'] = $rule_data[$field++];
215
				$flent['icmp_seq'] = $rule_data[$field++];
216
				$flent['icmp_otime'] = $rule_data[$field++];
217
				$flent['icmp_rtime'] = $rule_data[$field++];
218
				$flent['icmp_ttime'] = $rule_data[$field++];
219
				break;
220
			default :
221
				$flent['icmp_descr'] = $rule_data[$field++];
222
				break;
223
			}
224

    
225
		} else if ($flent['protoid'] == '112') { // CARP
226
			$flent['type'] = $rule_data[$field++];
227
			$flent['ttl'] = $rule_data[$field++];
228
			$flent['vhid'] = $rule_data[$field++];
229
			$flent['version'] = $rule_data[$field++];
230
			$flent['advskew'] = $rule_data[$field++];
231
			$flent['advbase'] = $rule_data[$field++];
232
		}
233
	} else {
234
		if($g['debug'])
235
			log_error(sprintf(gettext("There was a error parsing rule number: %s.   Please report to mailing list or forum."), $flent['rulenum']));
236
		return "";
237
	}
238

    
239
	/* If there is a src, a dst, and a time, then the line should be usable/good */
240
	if (!((trim($flent['src']) == "") || (trim($flent['dst']) == "") || (trim($flent['time']) == ""))) {
241
		return $flent;
242
	} else {
243
		if($g['debug']) {
244
			log_error(sprintf(gettext("There was a error parsing rule: %s.   Please report to mailing list or forum."), $errline));
245
		}
246
		return "";
247
	}
248
}
249

    
250
function get_port_with_service($port, $proto) {
251
	if (!$port)
252
		return '';
253

    
254
	$service = getservbyport($port, $proto);
255
	$portstr = "";
256
	if ($service) {
257
		$portstr = sprintf('<span title="' . gettext('Service %1$s/%2$s: %3$s') . '">' . htmlspecialchars($port) . '</span>', $port, $proto, $service);
258
	} else {
259
		$portstr = htmlspecialchars($port);
260
	}
261
	return ':' . $portstr;
262
}
263

    
264
function find_rule_by_number($rulenum, $trackernum, $type="block") {
265
	global $g;
266

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

    
271
	if ($trackernum == "0")
272
		$lookup_pattern = "^@{$rulenum}\([0-9]+\)[[:space:]]{$type}[[:space:]].*[[:space:]]log[[:space:]]";
273
	else
274
		$lookup_pattern = "^@[0-9]+\({$trackernum}\)[[:space:]]{$type}[[:space:]].*[[:space:]]log[[:space:]]";
275

    
276
	/* At the moment, miniupnpd is the only thing I know of that
277
	   generates logging rdr rules */
278
	unset($buffer);
279
	if ($type == "rdr")
280
		$_gb = exec("/sbin/pfctl -vvPsn -a \"miniupnpd\" | /usr/bin/egrep " . escapeshellarg("^@{$rulenum}"), $buffer);
281
	else {
282
		if (file_exists("{$g['tmp_path']}/rules.debug"))
283
			$_gb = exec("/sbin/pfctl -vvPnf {$g['tmp_path']}/rules.debug 2>/dev/null | /usr/bin/egrep " . escapeshellarg($lookup_pattern), $buffer);
284
		else
285
			$_gb = exec("/sbin/pfctl -vvPsr | /usr/bin/egrep " . escapeshellarg($lookup_pattern), $buffer);
286
	}
287
	if (is_array($buffer))
288
		return $buffer[0];
289

    
290
	return "";
291
}
292

    
293
function buffer_rules_load() {
294
	global $g, $buffer_rules_rdr, $buffer_rules_normal;
295
	unset($buffer, $buffer_rules_rdr, $buffer_rules_normal);
296
	/* Redeclare globals after unset to work around PHP */
297
	global $buffer_rules_rdr, $buffer_rules_normal;
298
	$buffer_rules_rdr = array();
299
	$buffer_rules_normal = array();
300

    
301
	$_gb = exec("/sbin/pfctl -vvPsn -a \"miniupnpd\" | grep '^@'", $buffer);
302
	if (is_array($buffer)) {
303
		foreach ($buffer as $line) {
304
			list($key, $value) = explode (" ", $line, 2);
305
			$buffer_rules_rdr[$key] = $value;
306
		}
307
	}
308
	unset($buffer, $_gb);
309
	if (file_exists("{$g['tmp_path']}/rules.debug"))
310
		$_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);
311
	else
312
		$_gb = exec("/sbin/pfctl -vvPsr | /usr/bin/egrep '^@[0-9]+\([0-9]+\)[[:space:]].*[[:space:]]log[[:space:]]'", $buffer);
313

    
314
	if (is_array($buffer)) {
315
		foreach ($buffer as $line) {
316
			list($key, $value) = explode (" ", $line, 2);
317
			# pfctl rule number output with tracker number: @dd(dddddddddd)
318
			$matches = array();
319
			if (preg_match('/\@(?P<rulenum>\d+)\((?<trackernum>\d+)\)/', $key, $matches) == 1) {
320
				if ($matches['trackernum'] > 0)
321
					$key = $matches['trackernum'];
322
				else
323
					$key = "@{$matches['rulenum']}";
324
			}
325
			$buffer_rules_normal[$key] = $value;
326
		}
327
	}
328
	unset($_gb, $buffer);
329
}
330

    
331
function buffer_rules_clear() {
332
	unset($GLOBALS['buffer_rules_normal']);
333
	unset($GLOBALS['buffer_rules_rdr']);
334
}
335

    
336
function find_rule_by_number_buffer($rulenum, $trackernum, $type){
337
	global $g, $buffer_rules_rdr, $buffer_rules_normal;
338

    
339
	if ($trackernum == "0")
340
		$lookup_key = "@{$rulenum}";
341
	else
342
		$lookup_key = $trackernum;
343

    
344
	if ($type == "rdr")	{
345
		$ruleString = $buffer_rules_rdr[$lookup_key];
346
		//TODO: get the correct 'description' part of a RDR log line. currently just first 30 characters..
347
		$rulename = substr($ruleString,0,30);
348
	} else {
349
		$ruleString = $buffer_rules_normal[$lookup_key];
350
		list(,$rulename,) = explode("\"",$ruleString);
351
		$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);
352
	}
353
	return "{$rulename} ({$lookup_key})";
354
}
355

    
356
function find_action_image($action) {
357
	global $g;
358
	if ((strstr(strtolower($action), "p")) || (strtolower($action) == "rdr"))
359
		return "/themes/{$g['theme']}/images/icons/icon_pass.gif";
360
	else if(strstr(strtolower($action), "r"))
361
		return "/themes/{$g['theme']}/images/icons/icon_reject.gif";
362
	else
363
		return "/themes/{$g['theme']}/images/icons/icon_block.gif";
364
}
365

    
366
/* AJAX specific handlers */
367
function handle_ajax($nentries, $tail = 50) {
368
	global $config;
369
	if($_GET['lastsawtime'] or $_POST['lastsawtime']) {
370
		global $filter_logfile,$filterent;
371
		if($_GET['lastsawtime'])
372
			$lastsawtime = $_GET['lastsawtime'];
373
		if($_POST['lastsawtime'])
374
			$lastsawtime = $_POST['lastsawtime'];
375
		/*  compare lastsawrule's time stamp to filter logs.
376
		 *  afterwards return the newer records so that client
377
		 *  can update AJAX interface screen.
378
		 */
379
		$new_rules = "";
380
		$filterlog = conv_log_filter($filter_logfile, $nentries, $tail);
381
		/* We need this to always be in forward order for the AJAX update to work properly */
382
		$filterlog = isset($config['syslog']['reverse']) ? array_reverse($filterlog) : $filterlog;
383
		foreach($filterlog as $log_row) {
384
			$row_time = strtotime($log_row['time']);
385
			$img = "<img border='0' src='" . find_action_image($log_row['act']) . "' alt={$log_row['act']} title={$log_row['act']} />";
386
			if($row_time > $lastsawtime) {
387
				if ($log_row['proto'] == "TCP")
388
					$log_row['proto'] .= ":{$log_row['tcpflags']}";
389

    
390
				$img = "<a href=\"#\" onClick=\"javascript:getURL('diag_logs_filter.php?getrulenum={$log_row['rulenum']},{$log_row['rulenum']}', outputrule);\">{$img}</a>";
391
				$new_rules .= "{$img}||{$log_row['time']}||{$log_row['interface']}||{$log_row['srcip']}||{$log_row['dst']}||{$log_row['proto']}||" . time() . "||\n";
392
			}
393
		}
394
		echo $new_rules;
395
		exit;
396
	}
397
}
398

    
399
?>
(20-20/67)