Projet

Général

Profil

Télécharger (11,6 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / filter_log.inc @ 26d060bc

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
/* format filter logs */
40
function conv_log_filter($logfile, $nentries, $tail = 50, $filtertext = "", $filterinterface = null) {
41
	global $config, $g;
42

    
43
	/* Make sure this is a number before using it in a system call */
44
	if (!(is_numeric($tail)))
45
		return;
46

    
47
	if ($filtertext)
48
		$tail = 5000;
49

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

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

    
58
	$filterlog = array();
59
	$counter = 0;
60

    
61
	$filterinterface = strtoupper($filterinterface);
62
	foreach ($logarr as $logent) {
63
		if($counter >= $nentries)
64
			break;
65

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

    
80
function match_filter_line($flent, $filtertext = "") {
81
	if (!$filtertext)
82
		return true;
83
	$filtertext = str_replace(' ', '\s+', $filtertext);
84
	return preg_match("/{$filtertext}/i", implode(" ", array_values($flent)));
85
}
86

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

    
105
// Case Insensitive in_array function
106
function in_arrayi($needle, $haystack) {
107
	return in_array(strtolower($needle), array_map('strtolower', $haystack));
108
}
109

    
110
function parse_filter_line($line) {
111
	global $config, $g;
112

    
113
	$flent = array();
114
	$log_split = "";
115

    
116
	if (!preg_match("/(.*)\s(.*)\sfilterlog:\s(.*)$/", $line, $log_split))
117
		return "";
118

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

    
121
	$rule_data = explode(",", $rule);
122
	$field = 0;
123

    
124
	$flent['rulenum'] = $rule_data[$field++];
125
	$flent['subrulenum'] = $rule_data[$field++];
126
	$flent['anchor'] = $rule_data[$field++];
127
	$flent['tracker'] = $rule_data[$field++];
128
	$flent['realint'] = $rule_data[$field++];
129
	$flent['interface']  = convert_real_interface_to_friendly_descr($flent['realint']);
130
	$flent['reason'] = $rule_data[$field++];
131
	$flent['act'] = $rule_data[$field++];
132
	$flent['direction'] = $rule_data[$field++];
133
	$flent['version'] = $rule_data[$field++];
134

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

    
153
		$flent['length'] = $rule_data[$field++];
154
		$flent['srcip'] = $rule_data[$field++];
155
		$flent['dstip'] = $rule_data[$field++];
156

    
157
		if ($flent['protoid'] == '6' || $flent['protoid'] == '17') { // TCP or UDP
158
			$flent['srcport'] = $rule_data[$field++];
159
			$flent['dstport'] = $rule_data[$field++];
160

    
161
			$flent['src'] = $flent['srcip'] . ':' . $flent['srcport'];
162
			$flent['dst'] = $flent['dstip'] . ':' . $flent['dstport'];
163

    
164
			$flent['datalen'] = $rule_data[$field++];
165
			if ($flent['protoid'] == '6') { // TCP
166
				$flent['tcpflags'] = $rule_data[$field++];
167
				$flent['seq'] = $rule_data[$field++];
168
				$flent['ack'] = $rule_data[$field++];
169
				$flent['window'] = $rule_data[$field++];
170
				$flent['urg'] = $rule_data[$field++];
171
				$flent['options'] = explode(";",$rule_data[$field++]);
172
			}
173
		} else if ($flent['protoid'] == '112') { // CARP
174
			$flent['type'] = $rule_data[$field++];
175
			$flent['ttl'] = $rule_data[$field++];
176
			$flent['vhid'] = $rule_data[$field++];
177
			$flent['version'] = $rule_data[$field++];
178
			$flent['advskew'] = $rule_data[$field++];
179
			$flent['advbase'] = $rule_data[$field++];
180
		}
181
	} else {
182
		if($g['debug'])
183
			log_error(sprintf(gettext("There was a error parsing rule number: %s.   Please report to mailing list or forum."), $flent['rulenum']));
184
		return "";
185
	}
186

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

    
198
function get_port_with_service($port, $proto) {
199
	if (!$port)
200
		return '';
201

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

    
212
function find_rule_by_number($rulenum, $type="rules") {
213
	global $g;
214

    
215
	/* Passing arbitrary input to grep could be a Very Bad Thing(tm) */
216
	if (!(is_numeric($rulenum)))
217
		return;
218
	/* At the moment, miniupnpd is the only thing I know of that
219
	   generates logging rdr rules */
220
	unset($buffer);
221
	if ($type == "rdr")
222
		$_gb = exec("/sbin/pfctl -vvPsn -a \"miniupnpd\" | grep '^@'", $buffer);
223
	else {
224
		if (file_exists("{$g['tmp_path']}/rules.debug"))
225
			$_gb = exec("/sbin/pfctl -vvPnf {$g['tmp_path']}/rules.debug 2>/dev/null | /usr/bin/egrep " . escapeshellarg("^@{$rulenum} {$type}"), $buffer);
226
		else
227
			$_gb = exec("/sbin/pfctl -vvPsr | grep " . escapeshellarg("^@{$rulenum}"), $buffer);
228
	}
229
	if (is_array($buffer))
230
		return $buffer[0];
231

    
232
	return "";
233
}
234

    
235
function buffer_rules_load() {
236
	global $g, $buffer_rules_rdr, $buffer_rules_normal;
237

    
238
	unset($buffer, $buffer_rules_rdr, $buffer_rules_normal);
239
	$buffer_rules_rdr = array();
240
	$buffer_rules_normal = array();
241

    
242
	$_gb = exec("/sbin/pfctl -vvPsn -a \"miniupnpd\" | grep '^@'", $buffer);
243
	if (is_array($buffer)) {
244
		foreach ($buffer as $line) {
245
			list($key, $value) = explode (" ", $line, 2);
246
			$buffer_rules_rdr[$key] = $value;
247
		}
248
	}
249
	unset($buffer, $_gb);
250
	if (file_exists("{$g['tmp_path']}/rules.debug"))
251
		$_gb = exec("/sbin/pfctl -vvPnf {$g['tmp_path']}/rules.debug 2>/dev/null | /usr/bin/egrep '^@[0-9]+ ' | /usr/bin/egrep -v '^@[0-9]+ (nat|rdr|binat|no|scrub)'", $buffer);
252
	else
253
		$_gb = exec("/sbin/pfctl -vvPsr | grep '^@'", $buffer);
254
	if (is_array($buffer)) {
255
		foreach ($buffer as $line) {
256
			list($key, $value) = explode (" ", $line, 2);
257
			$buffer_rules_normal[$key] = $value;
258
		}
259
	}
260
	unset($_gb, $buffer);
261
}
262

    
263
function buffer_rules_clear() {
264
	unset($GLOBALS['buffer_rules_normal']);
265
	unset($GLOBALS['buffer_rules_rdr']);
266
}
267

    
268
function find_rule_by_number_buffer($rulenum, $type){
269
	global $g, $buffer_rules_rdr, $buffer_rules_normal;
270
	
271
	if ($type == "rdr")	{
272
		$ruleString = $buffer_rules_rdr["@".$rulenum];
273
		//TODO: get the correct 'description' part of a RDR log line. currently just first 30 characters..
274
		$rulename = substr($ruleString,0,30);
275
	} else {
276
		$ruleString = $buffer_rules_normal["@".$rulenum];
277
		list(,$rulename,) = explode("\"",$ruleString);
278
		$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);
279
	}
280
	return $rulename." (@".$rulenum.")";
281
}
282

    
283
function find_action_image($action) {
284
	global $g;
285
	if ((strstr(strtolower($action), "p")) || (strtolower($action) == "rdr"))
286
		return "/themes/{$g['theme']}/images/icons/icon_pass.gif";
287
	else if(strstr(strtolower($action), "r"))
288
		return "/themes/{$g['theme']}/images/icons/icon_reject.gif";
289
	else
290
		return "/themes/{$g['theme']}/images/icons/icon_block.gif";
291
}
292

    
293
/* AJAX specific handlers */
294
function handle_ajax($nentries, $tail = 50) {
295
	global $config;
296
	if($_GET['lastsawtime'] or $_POST['lastsawtime']) {
297
		global $filter_logfile,$filterent;
298
		if($_GET['lastsawtime'])
299
			$lastsawtime = $_GET['lastsawtime'];
300
		if($_POST['lastsawtime'])
301
			$lastsawtime = $_POST['lastsawtime'];
302
		/*  compare lastsawrule's time stamp to filter logs.
303
		 *  afterwards return the newer records so that client
304
		 *  can update AJAX interface screen.
305
		 */
306
		$new_rules = "";
307
		$filterlog = conv_log_filter($filter_logfile, $nentries, $tail);
308
		/* We need this to always be in forward order for the AJAX update to work properly */
309
		$filterlog = isset($config['syslog']['reverse']) ? array_reverse($filterlog) : $filterlog;
310
		foreach($filterlog as $log_row) {
311
			$row_time = strtotime($log_row['time']);
312
			$img = "<img border='0' src='" . find_action_image($log_row['act']) . "' alt={$log_row['act']} title={$log_row['act']} />";
313
			if($row_time > $lastsawtime) {
314
				if ($log_row['proto'] == "TCP")
315
					$log_row['proto'] .= ":{$log_row['tcpflags']}";
316

    
317
				$img = "<a href=\"#\" onClick=\"javascript:getURL('diag_logs_filter.php?getrulenum={$log_row['rulenum']},{$log_row['rulenum']}', outputrule);\">{$img}</a>";
318
				$new_rules .= "{$img}||{$log_row['time']}||{$log_row['interface']}||{$log_row['srcip']}||{$log_row['dst']}||{$log_row['proto']}||" . time() . "||\n";
319
			}
320
		}
321
		echo $new_rules;
322
		exit;
323
	}
324
}
325

    
326
?>
(20-20/67)