Projet

Général

Profil

Télécharger (12,7 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / filter_log.inc @ 472455e8

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'] == '112') { // CARP
178
			$flent['type'] = $rule_data[$field++];
179
			$flent['ttl'] = $rule_data[$field++];
180
			$flent['vhid'] = $rule_data[$field++];
181
			$flent['version'] = $rule_data[$field++];
182
			$flent['advskew'] = $rule_data[$field++];
183
			$flent['advbase'] = $rule_data[$field++];
184
		}
185
	} else {
186
		if($g['debug'])
187
			log_error(sprintf(gettext("There was a error parsing rule number: %s.   Please report to mailing list or forum."), $flent['rulenum']));
188
		return "";
189
	}
190

    
191
	/* If there is a src, a dst, and a time, then the line should be usable/good */
192
	if (!((trim($flent['src']) == "") || (trim($flent['dst']) == "") || (trim($flent['time']) == ""))) {
193
		return $flent;
194
	} else {
195
		if($g['debug']) {
196
			log_error(sprintf(gettext("There was a error parsing rule: %s.   Please report to mailing list or forum."), $errline));
197
		}
198
		return "";
199
	}
200
}
201

    
202
function get_port_with_service($port, $proto) {
203
	if (!$port)
204
		return '';
205

    
206
	$service = getservbyport($port, $proto);
207
	$portstr = "";
208
	if ($service) {
209
		$portstr = sprintf('<span title="' . gettext('Service %1$s/%2$s: %3$s') . '">' . htmlspecialchars($port) . '</span>', $port, $proto, $service);
210
	} else {
211
		$portstr = htmlspecialchars($port);
212
	}
213
	return ':' . $portstr;
214
}
215

    
216
function find_rule_by_number($rulenum, $trackernum, $type="block") {
217
	global $g;
218

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

    
223
	if ($trackernum == "0")
224
		$lookup_pattern = "^@{$rulenum}\([0-9]+\)[[:space:]]{$type}[[:space:]].*[[:space:]]log[[:space:]]";
225
	else
226
		$lookup_pattern = "^@[0-9]+\({$trackernum}\)[[:space:]]{$type}[[:space:]].*[[:space:]]log[[:space:]]";
227

    
228
	/* At the moment, miniupnpd is the only thing I know of that
229
	   generates logging rdr rules */
230
	unset($buffer);
231
	if ($type == "rdr")
232
		$_gb = exec("/sbin/pfctl -vvPsn -a \"miniupnpd\" | /usr/bin/egrep " . escapeshellarg("^@{$rulenum}"), $buffer);
233
	else {
234
		if (file_exists("{$g['tmp_path']}/rules.debug"))
235
			$_gb = exec("/sbin/pfctl -vvPnf {$g['tmp_path']}/rules.debug 2>/dev/null | /usr/bin/egrep " . escapeshellarg($lookup_pattern), $buffer);
236
		else
237
			$_gb = exec("/sbin/pfctl -vvPsr | /usr/bin/egrep " . escapeshellarg($lookup_pattern), $buffer);
238
	}
239
	if (is_array($buffer))
240
		return $buffer[0];
241

    
242
	return "";
243
}
244

    
245
function buffer_rules_load() {
246
	global $g, $buffer_rules_rdr, $buffer_rules_normal;
247
	unset($buffer, $buffer_rules_rdr, $buffer_rules_normal);
248
	/* Redeclare globals after unset to work around PHP */
249
	global $buffer_rules_rdr, $buffer_rules_normal;
250
	$buffer_rules_rdr = array();
251
	$buffer_rules_normal = array();
252

    
253
	$_gb = exec("/sbin/pfctl -vvPsn -a \"miniupnpd\" | grep '^@'", $buffer);
254
	if (is_array($buffer)) {
255
		foreach ($buffer as $line) {
256
			list($key, $value) = explode (" ", $line, 2);
257
			$buffer_rules_rdr[$key] = $value;
258
		}
259
	}
260
	unset($buffer, $_gb);
261
	if (file_exists("{$g['tmp_path']}/rules.debug"))
262
		$_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);
263
	else
264
		$_gb = exec("/sbin/pfctl -vvPsr | /usr/bin/egrep '^@[0-9]+\([0-9]+\)[[:space:]].*[[:space:]]log[[:space:]]'", $buffer);
265

    
266
	if (is_array($buffer)) {
267
		foreach ($buffer as $line) {
268
			list($key, $value) = explode (" ", $line, 2);
269
			# pfctl rule number output with tracker number: @dd(dddddddddd)
270
			$matches = array();
271
			if (preg_match('/\@(?P<rulenum>\d+)\((?<trackernum>\d+)\)/', $key, $matches) == 1) {
272
				if ($matches['trackernum'] > 0)
273
					$key = $matches['trackernum'];
274
				else
275
					$key = "@{$matches['rulenum']}";
276
			}
277
			$buffer_rules_normal[$key] = $value;
278
		}
279
	}
280
	unset($_gb, $buffer);
281
}
282

    
283
function buffer_rules_clear() {
284
	unset($GLOBALS['buffer_rules_normal']);
285
	unset($GLOBALS['buffer_rules_rdr']);
286
}
287

    
288
function find_rule_by_number_buffer($rulenum, $trackernum, $type){
289
	global $g, $buffer_rules_rdr, $buffer_rules_normal;
290

    
291
	if ($trackernum == "0")
292
		$lookup_key = "@{$rulenum}";
293
	else
294
		$lookup_key = $trackernum;
295

    
296
	if ($type == "rdr")	{
297
		$ruleString = $buffer_rules_rdr[$lookup_key];
298
		//TODO: get the correct 'description' part of a RDR log line. currently just first 30 characters..
299
		$rulename = substr($ruleString,0,30);
300
	} else {
301
		$ruleString = $buffer_rules_normal[$lookup_key];
302
		list(,$rulename,) = explode("\"",$ruleString);
303
		$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);
304
	}
305
	return "{$rulename} ({$lookup_key})";
306
}
307

    
308
function find_action_image($action) {
309
	global $g;
310
	if ((strstr(strtolower($action), "p")) || (strtolower($action) == "rdr"))
311
		return "/themes/{$g['theme']}/images/icons/icon_pass.gif";
312
	else if(strstr(strtolower($action), "r"))
313
		return "/themes/{$g['theme']}/images/icons/icon_reject.gif";
314
	else
315
		return "/themes/{$g['theme']}/images/icons/icon_block.gif";
316
}
317

    
318
/* AJAX specific handlers */
319
function handle_ajax($nentries, $tail = 50) {
320
	global $config;
321
	if($_GET['lastsawtime'] or $_POST['lastsawtime']) {
322
		global $filter_logfile,$filterent;
323
		if($_GET['lastsawtime'])
324
			$lastsawtime = $_GET['lastsawtime'];
325
		if($_POST['lastsawtime'])
326
			$lastsawtime = $_POST['lastsawtime'];
327
		/*  compare lastsawrule's time stamp to filter logs.
328
		 *  afterwards return the newer records so that client
329
		 *  can update AJAX interface screen.
330
		 */
331
		$new_rules = "";
332
		$filterlog = conv_log_filter($filter_logfile, $nentries, $tail);
333
		/* We need this to always be in forward order for the AJAX update to work properly */
334
		$filterlog = isset($config['syslog']['reverse']) ? array_reverse($filterlog) : $filterlog;
335
		foreach($filterlog as $log_row) {
336
			$row_time = strtotime($log_row['time']);
337
			$img = "<img border='0' src='" . find_action_image($log_row['act']) . "' alt={$log_row['act']} title={$log_row['act']} />";
338
			if($row_time > $lastsawtime) {
339
				if ($log_row['proto'] == "TCP")
340
					$log_row['proto'] .= ":{$log_row['tcpflags']}";
341

    
342
				$img = "<a href=\"#\" onClick=\"javascript:getURL('diag_logs_filter.php?getrulenum={$log_row['rulenum']},{$log_row['rulenum']}', outputrule);\">{$img}</a>";
343
				$new_rules .= "{$img}||{$log_row['time']}||{$log_row['interface']}||{$log_row['srcip']}||{$log_row['dst']}||{$log_row['proto']}||" . time() . "||\n";
344
			}
345
		}
346
		echo $new_rules;
347
		exit;
348
	}
349
}
350

    
351
?>
(20-20/67)